0

I'm trying to load a folder of animation frames at compile time. The frames are named like this: frame1.png, frame2.png, ... frameN.png. Unfortunately after trying multiple methods for a while, I have come to the conclusion that this might not be possible. Am I correct?

Essentially the final data should look like this:

static DATA: &[&[u8]] &[
    [frame1 bytes],
    [frame2 bytes],
...
    [frameN bytes],
];

Here's what I've been trying to do:

macro_rules! import_img_anim {
    ($name:ident, $path:expr, $n:literal) => {
        static $name: &[&[u8]] = &[
            seq_macro::seq!(N in 1..=$n {
                include_bytes!(concat!($path, "/frame", stringify!(N), ".png")),
            })
        ];
    };
}

But the compiler gives this cryptic error message at include_bytes!: "macro expansion ignores token include_bytes and any following the usage of seq_macro::seq! is likely invalid in expression context"

Surely there's a way to do this? Rust's macros are widely regarded as immensely powerful, yet I can't even write a for loop in a comp-time context... (at least without including exernal crate)

5
  • "regarded as immensely powerful," that mostly applies to proc macros, declarative macros like you used are still quite powerful, but quite a bit less so than proc macros. Commented Feb 3 at 20:58
  • You forgot a comma. Commented Feb 3 at 21:06
  • I've tried with a comma and without and neither work Commented Feb 3 at 21:15
  • You can come up with a macro to do it (I did). The problem is that include_bytes! creates a sized array of bytes. So if you have a fixed frame size, you will have to specify it: play.rust-lang.org/… Commented Feb 3 at 21:15
  • You need to put the outer [] inside the seq! macro. Commented Feb 3 at 21:33

1 Answer 1

0

Okay I finally found the answer thanks to Eugene Sh.'s code:

use seq_macro::seq;

macro_rules! include_each {
    ($n:literal) => {
        seq!(N in 0..$n {
            [#(include_bytes!(stringify!(file~N)),)*]
        })
    };
}

const FRAME_SIZE: usize = 8;
static DATA: [&[u8; FRAME_SIZE]; 2] = include_each!(2);

Which I modified into this:

#[macro_export]
macro_rules! import_img_anim {
    ($path:literal, $n:literal, $extension:literal) => {
        seq_macro::seq!(N in 1..=$n {
            [#(include_bytes!(concat!($path, "/frame", stringify!(N), $extension)),)*]
        })
    };
}

The problem seemed to be this part of the code:

seq_macro::seq!(N in 1..=$n {
    include_bytes!(concat!($path, "/frame", stringify!(N), ".png")),
})

Which just put the include_bytes! macro there without anything else.

Thanks again Eugenne Sh.!

Sign up to request clarification or add additional context in comments.

3 Comments

I find it very helpful to have a key binding in VSCode (if you are using it) to expand macros.
Oh, that seems like a good idea. How can I do that? (Sorry if this isn't a relevant question in stack overflow...)
Ctrl+Shift+P and type/lookup "rust-analyzer: Expand macro recursively at caret". Then there is a cogwheel symbol next to it, which you click and configure the keyboard shortcut.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.