|
1 | 1 | // SPDX-License-Identifier: GPL-2.0
|
2 | 2 |
|
3 |
| -use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree}; |
| 3 | +use proc_macro::{token_stream, Delimiter, Group, Literal, TokenStream, TokenTree}; |
4 | 4 |
|
5 | 5 | fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
|
6 | 6 | 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
|
110 | 110 | byte_string
|
111 | 111 | }
|
112 | 112 |
|
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 | +} |
132 | 118 |
|
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 | + ) |
143 | 139 | } 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 | + }; |
151 | 143 |
|
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(); |
155 | 164 |
|
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 | + } |
165 | 167 |
|
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 | + } |
175 | 171 |
|
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 | + } |
180 | 175 |
|
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); |
186 | 179 | }
|
187 |
| -} |
188 | 180 |
|
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 | + } |
199 | 185 | }
|
200 | 186 |
|
201 | 187 | fn permissions_are_readonly(perms: &str) -> bool {
|
@@ -398,8 +384,24 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
398 | 384 |
|
399 | 385 | let name = info.name.clone();
|
400 | 386 |
|
| 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 | + |
401 | 404 | let mut array_types_to_generate = Vec::new();
|
402 |
| - let mut params_modinfo = String::new(); |
403 | 405 | if let Some(params) = info.params {
|
404 | 406 | assert_eq!(params.delimiter(), Delimiter::Brace);
|
405 | 407 |
|
@@ -444,18 +446,8 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
444 | 446 | }
|
445 | 447 | };
|
446 | 448 |
|
447 |
| - params_modinfo.push_str(&build_modinfo_string_param( |
448 |
| - &name, |
449 |
| - "parmtype", |
450 |
| - ¶m_name, |
451 |
| - ¶m_kernel_type, |
452 |
| - )); |
453 |
| - params_modinfo.push_str(&build_modinfo_string_param( |
454 |
| - &name, |
455 |
| - "parm", |
456 |
| - ¶m_name, |
457 |
| - ¶m_description, |
458 |
| - )); |
| 449 | + modinfo.emit_param("parmtype", ¶m_name, ¶m_kernel_type); |
| 450 | + modinfo.emit_param("parm", ¶m_name, ¶m_description); |
459 | 451 | let param_type_internal = match param_type {
|
460 | 452 | ParamType::Ident(ref param_type) => match param_type.as_ref() {
|
461 | 453 | "str" => "kernel::module_param::StringParam".to_string(),
|
@@ -504,7 +496,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
504 | 496 | name = name,
|
505 | 497 | param_name = param_name,
|
506 | 498 | );
|
507 |
| - params_modinfo.push_str( |
| 499 | + modinfo.buffer.push_str( |
508 | 500 | &format!(
|
509 | 501 | "
|
510 | 502 | static mut __{name}_{param_name}_value: {param_type_internal} = {param_default};
|
@@ -580,9 +572,6 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
580 | 572 | ));
|
581 | 573 | }
|
582 | 574 |
|
583 |
| - let file = |
584 |
| - std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); |
585 |
| - |
586 | 575 | format!(
|
587 | 576 | "
|
588 | 577 | /// The module name.
|
@@ -667,26 +656,13 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
667 | 656 | }}
|
668 | 657 | }}
|
669 | 658 |
|
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} |
679 | 660 |
|
680 | 661 | {generated_array_types}
|
681 | 662 | ",
|
682 | 663 | type_ = info.type_,
|
683 | 664 | 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, |
690 | 666 | generated_array_types = generated_array_types,
|
691 | 667 | initcall_section = ".initcall6.init"
|
692 | 668 | ).parse().expect("Error parsing formatted string into token stream.")
|
|
0 commit comments