Configuration profile with collection of collections stored as const?

Hi folks,

I have a struct CfProfile that stores configuration:

pub struct CfProfile {
    pub foo_items: Box<[Name]>,
    pub foo_items: Box<[AnotherConfig]>,
    pub bar_items: Box<[Name]>,
    pub bar_items: Box<[AnotherConfig]>,
    ...
}
pub enum Name {
    ...
}
pub struct AnotherConfig {
    ...
    items: Box<[OtherName]>
    ...
}
pub enum OtherName {
    ...
}

And multiple configuration profiles can be stored for example using enum like this:

pub enum CfProfiles {
    First(CfProfile),
    Second(CfProfile),
    ...
}

I'm using Boxed slices since all the configuration is immutable, and I think a Boxed slice is more efficient than a vector.

I didn't figure out how to store the profiles as const since some of the boxed slices have different numbers of elements, and obviously, arrays with different numbers of elements are different types.

I have multiple functions that request the configuration. The configuration profiles are simply defined inside a function that returns one of them, and it's obvious to me that this is super inefficient since every time a profile is requested, a lot of heap allocations are made and then dropped.

All functions that take pieces of the configuration accept a slice as an argument so elements in the configuration can be stored as any type of collection.

Could you please advise, is there a way to store it as a const?

Thank you.

You cannot create Box arrays in const. They always hold a heap allocation. Consider using &'static [T] instead.

4 Likes

Thank you. But static has the same problem as cons. Rust won't compile this:

pub struct CfProfile {
    pub foo1_items: Box<[Name]>,
    pub foo2_items: Box<[AnotherConfig]>,
    pub bar1_items: Box<[Name]>,
    pub bar2_items: Box<[AnotherConfig]>,
}
pub enum Name {
    Ab,
    Cd,
    Ef,
}
pub struct AnotherConfig {
    items: Box<[OtherName]>,
}
pub enum OtherName {
    Gh,
    Ij,
    Kl,
}

pub enum CfProfiles {
    First(CfProfile),
    Second(CfProfile),
}

static CF: CfProfile = CfProfile {
    foo1_items: Box::new([Name::Ab, Name::Cd]),
    foo2_items: Box::new([
        AnotherConfig {
            items: Box::new([OtherName::Gh, OtherName::Ij]),
        },
        AnotherConfig {
            items: Box::new([OtherName::Ij, OtherName::Kl]),
        },
    ]),
    bar1_items: Box::new([Name::Ab, Name::Cd, Name::Ef]),
    bar2_items: Box::new([AnotherConfig {
        items: Box::new([OtherName::Gh, OtherName::Ij, OtherName::Kl]),
    }]),
};

You are still using Box there. What @alice is suggesting is something like this:

pub struct CfProfile {
    pub foo1_items: &'static [Name],
    pub foo2_items: &'static [AnotherConfig],
    pub bar1_items: &'static [Name],
    pub bar2_items: &'static [AnotherConfig],
}
pub enum Name {
    Ab,
    Cd,
    Ef,
}
pub struct AnotherConfig {
    items: &'static [OtherName],
}
pub enum OtherName {
    Gh,
    Ij,
    Kl,
}

pub enum CfProfiles {
    First(CfProfile),
    Second(CfProfile),
}

static CF: CfProfile = CfProfile {
    foo1_items: &[Name::Ab, Name::Cd],
    foo2_items: &[
        AnotherConfig {
            items: &[OtherName::Gh, OtherName::Ij],
        },
        AnotherConfig {
            items: &[OtherName::Ij, OtherName::Kl],
        },
    ],
    bar1_items: &[Name::Ab, Name::Cd, Name::Ef],
    bar2_items: &[AnotherConfig {
        items: &[OtherName::Gh, OtherName::Ij, OtherName::Kl],
    }],
};

(playground)

This works with a const or a static.

4 Likes

Awesome! Thank you very much @jameseb7 and @alice !