Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Find alternatives to PHF for conditional compiling. #200

Open
CosminPerRam opened this issue Apr 21, 2024 · 3 comments
Open

feat: Find alternatives to PHF for conditional compiling. #200

CosminPerRam opened this issue Apr 21, 2024 · 3 comments
Labels
crate Stuff related to the crate in general dependencies Pull requests that update a dependency file game This is something regarding a game v1.0.X Things about v1.0.X
Milestone

Comments

@CosminPerRam
Copy link
Member

Describe the problem
When Ark: Survival Ascended was added in #197 we couldn't add it to the games definitions because the game (and protocol) is available only through the tls feature to avoid adding another hard dependency.

And we can't use conditional stuff with PHF in the way we use it now.

Possible solutions

  1. Swap phf with phf_codegen and create a build.rs script.
    Advantages: the fastest solution as this will generate and make the hashmap available at compile time.
    Disadvantages: negligible bigger compile time I guess? and I for one am not really a fan of build scripts.
  2. Use lazy_static! (or an equivalent).
    Advantages: Easiest to use and fastest to transition to.
    Disadvantages: The first call will take a while to compute (but considering that everything that we use is const, the only overhead should be just the hashmap construction and inserts (dont quote me on this)) and therefore isn't really great for CLI performance.
    Here is a quick snippet of a poc of the usage:
use std::collections::HashMap;
use lazy_static::lazy_static;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        #[cfg(feature = "some_feature")]
        m.insert(1, "baz");
        m
    };
}

fn main() {
    println!("{:#?}", HASHMAP.get(&1));
}
  1. Use phf for a 'default' hashmap and extend it with lazy_static only if we enable certain features.
    I haven't looked that much into this but it's something that came up when I wrote this.
@CosminPerRam CosminPerRam added game This is something regarding a game crate Stuff related to the crate in general dependencies Pull requests that update a dependency file labels Apr 21, 2024
@Douile
Copy link
Collaborator

Douile commented Apr 28, 2024

I don't think option 3 is possible because phf generates a hash function that is perfect for the things that exist at compile time. We would need 2 hash maps, then I guess to lookup check the phf one then the runtime one.

I don't think lazy static is a bad option: using normal hashmaps also allows the option for expanding game list at runtime.

There's also option 4 of adding support for cfg to the phf proc macro

Or option 5 of not feature gating tls, always have everything enabled. I'm not a big fan of that because it means consumers have less control of how they consume the library. However I don't imagine many situations where people wouldn't want tls support unless they just want a specific game.

@cainthebest cainthebest added the v1.0.X Things about v1.0.X label Sep 30, 2024
@cainthebest cainthebest added this to the v1.0.0-beta milestone Sep 30, 2024
@paul-hansen
Copy link

There is LazyLock in std as of Rust 1.80.0 if you want to avoid the extra dependency of lazystatic.

use std::collections::HashMap;
use std::sync::LazyLock;

const HASHMAP: LazyLock<HashMap<&str, &str>> = LazyLock::new(||{
    HashMap::from([
        ("conanexiles", "Conan Exiles"),
        #[cfg(feature="tls")]
        ("satisfactory", "Satisfactory"),
    ])
});

fn main() {
    println!("{:?}", HASHMAP.get("conanexiles"));
    println!("{:?}", HASHMAP.get("satisfactory"));
}

Playground

@cainthebest
Copy link
Collaborator

cainthebest commented Oct 21, 2024

There is LazyLock in std as of Rust 1.80.0 if you want to avoid the extra dependency of lazystatic.

use std::collections::HashMap;

use std::sync::LazyLock;



const HASHMAP: LazyLock<HashMap<&str, &str>> = LazyLock::new(||{

    HashMap::from([

        ("conanexiles", "Conan Exiles"),

        #[cfg(feature="tls")]

        ("satisfactory", "Satisfactory"),

    ])

});



fn main() {

    println!("{:?}", HASHMAP.get("conanexiles"));

    println!("{:?}", HASHMAP.get("satisfactory"));

}

Playground

Ty for the suggestion! The only thing with this method is the point that cosmin brought up about cost of init. There was a issue related to this for v0.5.X #219 but closed due to the msrv change. What i had in mind currently was using phf codegen to init a dict with those values at build time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crate Stuff related to the crate in general dependencies Pull requests that update a dependency file game This is something regarding a game v1.0.X Things about v1.0.X
Projects
None yet
Development

No branches or pull requests

4 participants