rust: macros: Allow specifying multiple module aliases

Modules can (and usually do) have multiple alias tags, in order to
specify multiple possible device matches for autoloading. Allow this by
changing the alias ModuleInfo field to an Option<Vec<String>>.

Note: For normal device IDs this is autogenerated by modpost (which is
not properly integrated with Rust support yet), so it is useful to be
able to manually add device match aliases for now, and should still be
useful in the future for corner cases that modpost does not handle.

This pulls in the expect_group() helper from the rfl/rust branch
(with credit to authors).

Co-developed-by: Miguel Ojeda <[email protected]>
Signed-off-by: Miguel Ojeda <[email protected]>
Co-developed-by: Finn Behrens <[email protected]>
Signed-off-by: Finn Behrens <[email protected]>
Co-developed-by: Sumera Priyadarsini <[email protected]>
Signed-off-by: Sumera Priyadarsini <[email protected]>
Reviewed-by: Vincenzo Palazzo <[email protected]>
Signed-off-by: Asahi Lina <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Miguel Ojeda <[email protected]>
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index a7e363c..5e7ab83 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -1,9 +1,27 @@
 // SPDX-License-Identifier: GPL-2.0
 
 use crate::helpers::*;
-use proc_macro::{token_stream, Literal, TokenStream, TokenTree};
+use proc_macro::{token_stream, Delimiter, Literal, TokenStream, TokenTree};
 use std::fmt::Write;
 
+fn expect_string_array(it: &mut token_stream::IntoIter) -> Vec<String> {
+    let group = expect_group(it);
+    assert_eq!(group.delimiter(), Delimiter::Bracket);
+    let mut values = Vec::new();
+    let mut it = group.stream().into_iter();
+
+    while let Some(val) = try_string(&mut it) {
+        assert!(val.is_ascii(), "Expected ASCII string");
+        values.push(val);
+        match it.next() {
+            Some(TokenTree::Punct(punct)) => assert_eq!(punct.as_char(), ','),
+            None => break,
+            _ => panic!("Expected ',' or end of array"),
+        }
+    }
+    values
+}
+
 struct ModInfoBuilder<'a> {
     module: &'a str,
     counter: usize,
@@ -78,7 +96,7 @@
     name: String,
     author: Option<String>,
     description: Option<String>,
-    alias: Option<String>,
+    alias: Option<Vec<String>>,
 }
 
 impl ModuleInfo {
@@ -112,7 +130,7 @@
                 "author" => info.author = Some(expect_string(it)),
                 "description" => info.description = Some(expect_string(it)),
                 "license" => info.license = expect_string_ascii(it),
-                "alias" => info.alias = Some(expect_string_ascii(it)),
+                "alias" => info.alias = Some(expect_string_array(it)),
                 _ => panic!(
                     "Unknown key \"{}\". Valid keys are: {:?}.",
                     key, EXPECTED_KEYS
@@ -163,8 +181,10 @@
         modinfo.emit("description", &description);
     }
     modinfo.emit("license", &info.license);
-    if let Some(alias) = info.alias {
-        modinfo.emit("alias", &alias);
+    if let Some(aliases) = info.alias {
+        for alias in aliases {
+            modinfo.emit("alias", &alias);
+        }
     }
 
     // Built-in modules also export the `file` modinfo string.