|
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