Skip to content

Commit 23b0a16

Browse files
committed
rust: cleanup modinfo generation in module!
Signed-off-by: Gary Guo <gary@garyguo.net>
1 parent a8079fc commit 23b0a16

File tree

1 file changed

+86
-110
lines changed

1 file changed

+86
-110
lines changed

rust/macros/module.rs

Lines changed: 86 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3-
use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree};
3+
use proc_macro::{token_stream, Delimiter, Group, Literal, TokenStream, TokenTree};
44

55
fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
66
if let Some(TokenTree::Ident(ident)) = it.next() {
@@ -110,92 +110,78 @@ fn get_byte_string(it: &mut token_stream::IntoIter, expected_name: &str) -> Stri
110110
byte_string
111111
}
112112

113-
fn __build_modinfo_string_base(
114-
module: &str,
115-
field: &str,
116-
content: &str,
117-
variable: &str,
118-
builtin: bool,
119-
) -> String {
120-
let string = if builtin {
121-
// Built-in modules prefix their modinfo strings by `module.`.
122-
format!(
123-
"{module}.{field}={content}",
124-
module = module,
125-
field = field,
126-
content = content
127-
)
128-
} else {
129-
// Loadable modules' modinfo strings go as-is.
130-
format!("{field}={content}", field = field, content = content)
131-
};
113+
struct ModInfoBuilder<'a> {
114+
module: &'a str,
115+
counter: usize,
116+
buffer: String,
117+
}
132118

133-
format!(
134-
"
135-
{cfg}
136-
#[doc(hidden)]
137-
#[link_section = \".modinfo\"]
138-
#[used]
139-
pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
140-
",
141-
cfg = if builtin {
142-
"#[cfg(not(MODULE))]"
119+
impl<'a> ModInfoBuilder<'a> {
120+
fn new(module: &'a str) -> Self {
121+
ModInfoBuilder {
122+
module,
123+
counter: 0,
124+
buffer: String::new(),
125+
}
126+
}
127+
128+
fn emit_base(&mut self, field: &str, content: &str, builtin: bool) {
129+
use std::fmt::Write;
130+
131+
let string = if builtin {
132+
// Built-in modules prefix their modinfo strings by `module.`.
133+
format!(
134+
"{module}.{field}={content}\0",
135+
module = self.module,
136+
field = field,
137+
content = content
138+
)
143139
} else {
144-
"#[cfg(MODULE)]"
145-
},
146-
variable = variable,
147-
length = string.len() + 1,
148-
string = string,
149-
)
150-
}
140+
// Loadable modules' modinfo strings go as-is.
141+
format!("{field}={content}\0", field = field, content = content)
142+
};
151143

152-
fn __build_modinfo_string_variable(module: &str, field: &str) -> String {
153-
format!("__{module}_{field}", module = module, field = field)
154-
}
144+
write!(
145+
&mut self.buffer,
146+
"
147+
{cfg}
148+
#[doc(hidden)]
149+
#[link_section = \".modinfo\"]
150+
#[used]
151+
pub static __{module}_{counter}: [u8; {length}] = *{string};
152+
",
153+
cfg = if builtin {
154+
"#[cfg(not(MODULE))]"
155+
} else {
156+
"#[cfg(MODULE)]"
157+
},
158+
module = self.module,
159+
counter = self.counter,
160+
length = string.len(),
161+
string = Literal::byte_string(string.as_bytes()),
162+
)
163+
.unwrap();
155164

156-
fn build_modinfo_string_only_builtin(module: &str, field: &str, content: &str) -> String {
157-
__build_modinfo_string_base(
158-
module,
159-
field,
160-
content,
161-
&__build_modinfo_string_variable(module, field),
162-
true,
163-
)
164-
}
165+
self.counter += 1;
166+
}
165167

166-
fn build_modinfo_string_only_loadable(module: &str, field: &str, content: &str) -> String {
167-
__build_modinfo_string_base(
168-
module,
169-
field,
170-
content,
171-
&__build_modinfo_string_variable(module, field),
172-
false,
173-
)
174-
}
168+
fn emit_only_builtin(&mut self, field: &str, content: &str) {
169+
self.emit_base(field, content, true)
170+
}
175171

176-
fn build_modinfo_string(module: &str, field: &str, content: &str) -> String {
177-
build_modinfo_string_only_builtin(module, field, content)
178-
+ &build_modinfo_string_only_loadable(module, field, content)
179-
}
172+
fn emit_only_loadable(&mut self, field: &str, content: &str) {
173+
self.emit_base(field, content, false)
174+
}
180175

181-
fn build_modinfo_string_optional(module: &str, field: &str, content: Option<&str>) -> String {
182-
if let Some(content) = content {
183-
build_modinfo_string(module, field, content)
184-
} else {
185-
"".to_string()
176+
fn emit(&mut self, field: &str, content: &str) {
177+
self.emit_only_builtin(field, content);
178+
self.emit_only_loadable(field, content);
186179
}
187-
}
188180

189-
fn build_modinfo_string_param(module: &str, field: &str, param: &str, content: &str) -> String {
190-
let variable = format!(
191-
"__{module}_{field}_{param}",
192-
module = module,
193-
field = field,
194-
param = param
195-
);
196-
let content = format!("{param}:{content}", param = param, content = content);
197-
__build_modinfo_string_base(module, field, &content, &variable, true)
198-
+ &__build_modinfo_string_base(module, field, &content, &variable, false)
181+
fn emit_param(&mut self, field: &str, param: &str, content: &str) {
182+
let content = format!("{param}:{content}", param = param, content = content);
183+
self.emit(field, &content);
184+
}
199185
}
200186

201187
fn permissions_are_readonly(perms: &str) -> bool {
@@ -398,8 +384,24 @@ pub fn module(ts: TokenStream) -> TokenStream {
398384

399385
let name = info.name.clone();
400386

387+
let mut modinfo = ModInfoBuilder::new(&name);
388+
if let Some(author) = info.author {
389+
modinfo.emit("author", &author);
390+
}
391+
if let Some(description) = info.description {
392+
modinfo.emit("description", &description);
393+
}
394+
modinfo.emit("license", &info.license);
395+
if let Some(alias) = info.alias {
396+
modinfo.emit("alias", &alias);
397+
}
398+
399+
// Built-in modules also export the `file` modinfo string
400+
let file =
401+
std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
402+
modinfo.emit_only_builtin("file", &file);
403+
401404
let mut array_types_to_generate = Vec::new();
402-
let mut params_modinfo = String::new();
403405
if let Some(params) = info.params {
404406
assert_eq!(params.delimiter(), Delimiter::Brace);
405407

@@ -444,18 +446,8 @@ pub fn module(ts: TokenStream) -> TokenStream {
444446
}
445447
};
446448

447-
params_modinfo.push_str(&build_modinfo_string_param(
448-
&name,
449-
"parmtype",
450-
&param_name,
451-
&param_kernel_type,
452-
));
453-
params_modinfo.push_str(&build_modinfo_string_param(
454-
&name,
455-
"parm",
456-
&param_name,
457-
&param_description,
458-
));
449+
modinfo.emit_param("parmtype", &param_name, &param_kernel_type);
450+
modinfo.emit_param("parm", &param_name, &param_description);
459451
let param_type_internal = match param_type {
460452
ParamType::Ident(ref param_type) => match param_type.as_ref() {
461453
"str" => "kernel::module_param::StringParam".to_string(),
@@ -504,7 +496,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
504496
name = name,
505497
param_name = param_name,
506498
);
507-
params_modinfo.push_str(
499+
modinfo.buffer.push_str(
508500
&format!(
509501
"
510502
static mut __{name}_{param_name}_value: {param_type_internal} = {param_default};
@@ -580,9 +572,6 @@ pub fn module(ts: TokenStream) -> TokenStream {
580572
));
581573
}
582574

583-
let file =
584-
std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
585-
586575
format!(
587576
"
588577
/// The module name.
@@ -667,26 +656,13 @@ pub fn module(ts: TokenStream) -> TokenStream {
667656
}}
668657
}}
669658
670-
{author}
671-
{description}
672-
{license}
673-
{alias}
674-
675-
// Built-in modules also export the `file` modinfo string
676-
{file}
677-
678-
{params_modinfo}
659+
{modinfo}
679660
680661
{generated_array_types}
681662
",
682663
type_ = info.type_,
683664
name = info.name,
684-
author = &build_modinfo_string_optional(&name, "author", info.author.as_deref()),
685-
description = &build_modinfo_string_optional(&name, "description", info.description.as_deref()),
686-
license = &build_modinfo_string(&name, "license", &info.license),
687-
alias = &build_modinfo_string_optional(&name, "alias", info.alias.as_deref()),
688-
file = &build_modinfo_string_only_builtin(&name, "file", &file),
689-
params_modinfo = params_modinfo,
665+
modinfo = modinfo.buffer,
690666
generated_array_types = generated_array_types,
691667
initcall_section = ".initcall6.init"
692668
).parse().expect("Error parsing formatted string into token stream.")

0 commit comments

Comments
 (0)