This macro works for literals (although it is a bit ugly because I let an LLM give me the initial version. I just cannot remember macro_rules syntax...).
macro_rules! carthesian {
// Recursive case: take the first element from the first list, and for each element in the second list,
// append the concatenated string to the accumulator. Then recurse with the rest of the first list.
( [$first:expr $(, $rest:expr)*], [$($second:expr),* $(,)?]; [$($acc:expr),* $(,)?] ) => {
carthesian!(
[ $($rest),* ],
[$($second),*];
[
$($acc,)*
$(concat!($first, $second)),*
]
)
};
// Base case: when no more elements remain in the first list, return the accumulated array.
( [], [$($second:expr),* $(,)?]; [$($acc:expr),* $(,)?] ) => {
[$($acc),*]
};
( [$($first:expr),* $(,)?], [$($second:expr),* $(,)?] ) => {
carthesian!([ $($first),* ], [$($second),*]; [])
};
}
Unicode-compatible capitalization, maybe not as trivial, you’d probably have to copy some case conversion tables from the standard library internals for a constified implementation of it.. unless some crate already has const-compatible versions of it.
Edit: This implementation is unnecessarily convoluted. Check the next comment for a better approach.
Thank you very much to those who answered.
I tried @Bruecki and @steffahn solutions and they both seemed to work, so I went and attempted to solve the last part.
This is a link to the playground with my solution -- even though it doesn't compile since it has no access to seq-macro. I thought posting the link would be better than slamming the 150 lines here. It does work locally.
I apologize if the code happens to be obscure, I am not sure about what's idiomatic in these cases.
For the context, the problem is:
Capitalize (only the first letter) a non-ascii const &str (in my case, only Greek)
After reading again @steffahn solution, I applied the same ideas for the second part. This is much cleaner than my previous version and does not require seq-macro so I can now finally post a playground that works.
// Both of these arrays can contain non-ascii chars
const LEMMAS: [&str; 2] = ["ab", "γδ"];
const ENDINGS: [&str; 3] = ["1", "2", "3"];
const EXPANDED_MANUAL: [&str; 6] = ["ab1", "ab2", "ab3", "γδ1", "γδ2", "γδ3"];
const EXPANDED: [&str; 6] = expand!(LEMMAS, ENDINGS);
// It is fine if the ascii strings remain as it is.
// For my usecase, LEMMAS and ENDINGS are guaranteed to always be Greek.
const EXPECTED: [&str; 12] = [
"ab1", "ab1", "ab2", "ab2", "ab3", "ab3",
"γδ1", "Γδ1", "γδ2", "Γδ2", "γδ3", "Γδ3",
];
const RESULT: [&str; 12] = expand_with_capitalized!(LEMMAS, ENDINGS);
fn main() {
assert_eq!(EXPANDED_MANUAL, EXPANDED);
assert_eq!(EXPECTED, RESULT);
}
I will chose his comment as the preferred solution since it solves the first part of my question and pretty much the second part too (I wish I could have seen that earlier!).