How to initiate a large Rust map 'statically'

I have the following C++ structure that I want to rewrite in Rust:

struct Fraction
{
    int numerator;
    int denominator;
};

struct PixelFormat
{
    Fraction yuvSizes[3];
    Fraction yuvWidths[3];
    Fraction yuvHeights[3];
    int yuvInternalFormat[3];
    int yuvGlFormat[3];
    int textureFormat;
    bool isPlanar;
    int dataType;
    std::string humanReadablePixelFormat;
};

I need to access this map fast. It cannot be an array, unfortunately.

I initiate them in C++ statically like this:

static std::map<int, PixelFormat> pixelFormats;

pixelFormats[AV_PIX_FMT_YUV420P] = PixelFormat {
    //Fraction yuvSizes[3];
    {one,one,one},
    //Fraction yuvWidths[3];
    {one,two,two},
    //Fraction yuvHeights[3];
    {one,two,two},
    //GLint yuvInternalFormat[3];
    {GL_SYMBOLS::GL__RED,GL_SYMBOLS::GL__RED,GL_SYMBOLS::GL__RED},
    //GLenum yuvGlFormat[3];
    {GL_SYMBOLS::GL__RED,GL_SYMBOLS::GL__RED,GL_SYMBOLS::GL__RED},
    //int textureFormat
    YUV,
    //bool isPlanar
    true,
    //GLenum dataType
    GL_SYMBOLS::GL__UNSIGNED_BYTE,
    //std::string humanReadablePixelFormat
    "AV_PIX_FMT_YUV420P"
};

This is generated by a python script. It's a table of color conversions for video. Everything is constant.

On Rust there is no static so I'm confused on a good way of doing this map. Ideally I'd like something like this:

const pixel_formats: Map<PixelFormat> = {
    AV_PIX_FMT_YUV420P => Fraction{
    //...

    }
    //...
}

Maybe a map is too much and there's something lighter on Rust?

Because HashMaps live on the heap, I don't think it's usually possible to declare them with const. You can somewhat get around this with lazy_static, but there is a cost involved, especially if you access the map frequently.

In your C++ code the map isn't initialized statically. Its initializer is evaluated at runtime, before the main() is called.

Rust as a language, unlike C++, doesn't provide a way to run custom code before main(). Usually globals which requires runtime-initialization are lazily initialized just before the first use. You can use lazy_static or once_cell crate for it. Both are popular and well-tested.

But it seems your int is not really an integer but an enum. Rust has real enum with exhaustive matching so it would be better to make a script-generated mapping function with giant match instead of the maps.

3 Likes

If you only have a handful of entries, a static array works fine.

1 Like

Try https://crates.io/crates/phf

But if I were you, I would actually make it load from a JSON file that I can change/modify later on without recompiling...

I'm trying

static KEYWORDS: phf::Map<AVPixelFormat, PixelFormat> = phf_map! {
    AVPixelFormat::AV_PIX_FMT_YUV420P => PixelFormat {

but I'm getting "unsupported key expression" on AVPixelFormat::AV_PIX_FMT_YUV420P. Are you sure it works with enum? My enum is AVPixelFormat

I remember it does work with enum's, but it was a long while ago and I since stopped incorporating pre-compiled static data into my app.

But I suppose it doesn't work with enums as keys. Try assigning a number to each enum variant and use those numbers as keys.

Based on my memory, you only need to cast the first line to the number type, then all the rest will follow.