|
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,91 +110,77 @@ 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 |
| - #[link_section = \".modinfo\"] |
137 |
| - #[used] |
138 |
| - pub static {variable}: [u8; {length}] = *b\"{string}\\0\"; |
139 |
| - ", |
140 |
| - cfg = if builtin { |
141 |
| - "#[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 | + ) |
142 | 139 | } else {
|
143 |
| - "#[cfg(MODULE)]" |
144 |
| - }, |
145 |
| - variable = variable, |
146 |
| - length = string.len() + 1, |
147 |
| - string = string, |
148 |
| - ) |
149 |
| -} |
| 140 | + // Loadable modules' modinfo strings go as-is. |
| 141 | + format!("{field}={content}\0", field = field, content = content) |
| 142 | + }; |
150 | 143 |
|
151 |
| -fn __build_modinfo_string_variable(module: &str, field: &str) -> String { |
152 |
| - format!("__{module}_{field}", module = module, field = field) |
153 |
| -} |
| 144 | + write!( |
| 145 | + &mut self.buffer, |
| 146 | + " |
| 147 | + {cfg} |
| 148 | + #[link_section = \".modinfo\"] |
| 149 | + #[used] |
| 150 | + pub static __{module}_{counter}: [u8; {length}] = *{string}; |
| 151 | + ", |
| 152 | + cfg = if builtin { |
| 153 | + "#[cfg(not(MODULE))]" |
| 154 | + } else { |
| 155 | + "#[cfg(MODULE)]" |
| 156 | + }, |
| 157 | + module = self.module, |
| 158 | + counter = self.counter, |
| 159 | + length = string.len(), |
| 160 | + string = Literal::byte_string(string.as_bytes()), |
| 161 | + ) |
| 162 | + .unwrap(); |
154 | 163 |
|
155 |
| -fn build_modinfo_string_only_builtin(module: &str, field: &str, content: &str) -> String { |
156 |
| - __build_modinfo_string_base( |
157 |
| - module, |
158 |
| - field, |
159 |
| - content, |
160 |
| - &__build_modinfo_string_variable(module, field), |
161 |
| - true, |
162 |
| - ) |
163 |
| -} |
| 164 | + self.counter += 1; |
| 165 | + } |
164 | 166 |
|
165 |
| -fn build_modinfo_string_only_loadable(module: &str, field: &str, content: &str) -> String { |
166 |
| - __build_modinfo_string_base( |
167 |
| - module, |
168 |
| - field, |
169 |
| - content, |
170 |
| - &__build_modinfo_string_variable(module, field), |
171 |
| - false, |
172 |
| - ) |
173 |
| -} |
| 167 | + fn emit_only_builtin(&mut self, field: &str, content: &str) { |
| 168 | + self.emit_base(field, content, true) |
| 169 | + } |
174 | 170 |
|
175 |
| -fn build_modinfo_string(module: &str, field: &str, content: &str) -> String { |
176 |
| - build_modinfo_string_only_builtin(module, field, content) |
177 |
| - + &build_modinfo_string_only_loadable(module, field, content) |
178 |
| -} |
| 171 | + fn emit_only_loadable(&mut self, field: &str, content: &str) { |
| 172 | + self.emit_base(field, content, false) |
| 173 | + } |
179 | 174 |
|
180 |
| -fn build_modinfo_string_optional(module: &str, field: &str, content: Option<&str>) -> String { |
181 |
| - if let Some(content) = content { |
182 |
| - build_modinfo_string(module, field, content) |
183 |
| - } else { |
184 |
| - "".to_string() |
| 175 | + fn emit(&mut self, field: &str, content: &str) { |
| 176 | + self.emit_only_builtin(field, content); |
| 177 | + self.emit_only_loadable(field, content); |
185 | 178 | }
|
186 |
| -} |
187 | 179 |
|
188 |
| -fn build_modinfo_string_param(module: &str, field: &str, param: &str, content: &str) -> String { |
189 |
| - let variable = format!( |
190 |
| - "__{module}_{field}_{param}", |
191 |
| - module = module, |
192 |
| - field = field, |
193 |
| - param = param |
194 |
| - ); |
195 |
| - let content = format!("{param}:{content}", param = param, content = content); |
196 |
| - __build_modinfo_string_base(module, field, &content, &variable, true) |
197 |
| - + &__build_modinfo_string_base(module, field, &content, &variable, false) |
| 180 | + fn emit_param(&mut self, field: &str, param: &str, content: &str) { |
| 181 | + let content = format!("{param}:{content}", param = param, content = content); |
| 182 | + self.emit(field, &content); |
| 183 | + } |
198 | 184 | }
|
199 | 185 |
|
200 | 186 | fn permissions_are_readonly(perms: &str) -> bool {
|
@@ -397,8 +383,24 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
397 | 383 |
|
398 | 384 | let name = info.name.clone();
|
399 | 385 |
|
| 386 | + let mut modinfo = ModInfoBuilder::new(&name); |
| 387 | + if let Some(author) = info.author { |
| 388 | + modinfo.emit("author", &author); |
| 389 | + } |
| 390 | + if let Some(description) = info.description { |
| 391 | + modinfo.emit("description", &description); |
| 392 | + } |
| 393 | + modinfo.emit("license", &info.license); |
| 394 | + if let Some(alias) = info.alias { |
| 395 | + modinfo.emit("alias", &alias); |
| 396 | + } |
| 397 | + |
| 398 | + // Built-in modules also export the `file` modinfo string |
| 399 | + let file = |
| 400 | + std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); |
| 401 | + modinfo.emit_only_builtin("file", &file); |
| 402 | + |
400 | 403 | let mut array_types_to_generate = Vec::new();
|
401 |
| - let mut params_modinfo = String::new(); |
402 | 404 | if let Some(params) = info.params {
|
403 | 405 | assert_eq!(params.delimiter(), Delimiter::Brace);
|
404 | 406 |
|
@@ -443,18 +445,8 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
443 | 445 | }
|
444 | 446 | };
|
445 | 447 |
|
446 |
| - params_modinfo.push_str(&build_modinfo_string_param( |
447 |
| - &name, |
448 |
| - "parmtype", |
449 |
| - ¶m_name, |
450 |
| - ¶m_kernel_type, |
451 |
| - )); |
452 |
| - params_modinfo.push_str(&build_modinfo_string_param( |
453 |
| - &name, |
454 |
| - "parm", |
455 |
| - ¶m_name, |
456 |
| - ¶m_description, |
457 |
| - )); |
| 448 | + modinfo.emit_param("parmtype", ¶m_name, ¶m_kernel_type); |
| 449 | + modinfo.emit_param("parm", ¶m_name, ¶m_description); |
458 | 450 | let param_type_internal = match param_type {
|
459 | 451 | ParamType::Ident(ref param_type) => match param_type.as_ref() {
|
460 | 452 | "str" => "kernel::module_param::StringParam".to_string(),
|
@@ -503,7 +495,7 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
503 | 495 | name = name,
|
504 | 496 | param_name = param_name,
|
505 | 497 | );
|
506 |
| - params_modinfo.push_str( |
| 498 | + modinfo.buffer.push_str( |
507 | 499 | &format!(
|
508 | 500 | "
|
509 | 501 | static mut __{name}_{param_name}_value: {param_type_internal} = {param_default};
|
@@ -579,9 +571,6 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
579 | 571 | ));
|
580 | 572 | }
|
581 | 573 |
|
582 |
| - let file = |
583 |
| - std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); |
584 |
| - |
585 | 574 | format!(
|
586 | 575 | "
|
587 | 576 | /// The module name.
|
@@ -661,26 +650,13 @@ pub fn module(ts: TokenStream) -> TokenStream {
|
661 | 650 | }}
|
662 | 651 | }}
|
663 | 652 |
|
664 |
| - {author} |
665 |
| - {description} |
666 |
| - {license} |
667 |
| - {alias} |
668 |
| -
|
669 |
| - // Built-in modules also export the `file` modinfo string |
670 |
| - {file} |
671 |
| -
|
672 |
| - {params_modinfo} |
| 653 | + {modinfo} |
673 | 654 |
|
674 | 655 | {generated_array_types}
|
675 | 656 | ",
|
676 | 657 | type_ = info.type_,
|
677 | 658 | name = info.name,
|
678 |
| - author = &build_modinfo_string_optional(&name, "author", info.author.as_deref()), |
679 |
| - description = &build_modinfo_string_optional(&name, "description", info.description.as_deref()), |
680 |
| - license = &build_modinfo_string(&name, "license", &info.license), |
681 |
| - alias = &build_modinfo_string_optional(&name, "alias", info.alias.as_deref()), |
682 |
| - file = &build_modinfo_string_only_builtin(&name, "file", &file), |
683 |
| - params_modinfo = params_modinfo, |
| 659 | + modinfo = modinfo.buffer, |
684 | 660 | generated_array_types = generated_array_types,
|
685 | 661 | initcall_section = ".initcall6.init"
|
686 | 662 | ).parse().expect("Error parsing formatted string into token stream.")
|
|
0 commit comments