Skip to content

Conversation

@mplanchard
Copy link
Contributor

We have a use case where we'd like to maintain a static list of
countries to check some values against, e.g.:

const COUNTRIES_TO_CHECK: &[Country] = [
      Country::the_united_states_of_america(),
      Country::canada(),
];

We could just use the 3-letter codes, but it would be nice to have the
entire Country object for more flexibility (e.g. to check against
either 2-letter or 3-letter inputs), and without needing a workaround
like:

COUNTRIES_TO_CHECK
    .map(|code| Country::from_code(code).expect("known valid country"))
    .any(|country| country.alpha2 == val || country.alpha3 == val)

This PR updates the country and lookup macros to enable const
construction of Country tables, so that country construction can be
used in const contexts.


In a second commit, I have updated the const functions to use inline
const blocks. This will guarantee that country resolution is always
evaluated at compile time, allowing the cost to be ~zero at runtime,
even outside of const contexts. This requires Rust 1.79, so I have
added a rust-version property to Cargo.toml to indicate the MSRV
(released June, 2024). If you'd prefer to not add a feature requiring
an MSRV, let me know and I can drop that commit.

We have a use case where we'd like to maintain a static list of
countries to check some values against, e.g.:

```rust
const COUNTRIES_TO_CHECK: &[Country] = [
      Country::the_united_states_of_america(),
      Country::canada(),
];
```

We could just use the 3-letter codes, but it would be nice to have the
entire Country object for more flexibility (e.g. to check against
either 2-letter or 3-letter inputs), and without needing a workaround
like:

```rust
COUNTRIES_TO_CHECK
    .map(|code| Country::from_code(code).expect("known valid country"))
    .any(|country| country.alpha2 == val || country.alpha3 == val)
```

This PR updates the `country` and `lookup` macros to enable const
construction of `Country` tables, so that country construction can be
used in const contexts.
@mplanchard
Copy link
Contributor Author

Ah, the LazyLock invocations already required Rust 1.80, so I'll update the MSRV to that.

@mplanchard
Copy link
Contributor Author

Note that this also paves the way to making all of the lookup functions reliant on match statements rather than lazy static hashmap lookups.

That could go either way, with values either mapping to e.g. "us" => Some(const { Country::the_united_states_of_america() }), or we could define consts for every country as part of the country! macro, which would allow like "us" => Some(Self::THE_UNITED_STATES_OF_AMERICA). The latter would be preferable if you'd be interested in exposing the consts in the public interface. Otherwise it's 6 of one, 1/2 dozen of the other.

If you're interested in this as a followup, lmk and I'll open a PR.

@mikelodder7
Copy link
Owner

Yeah I agree. Its time to update this.

@mikelodder7 mikelodder7 merged commit b3a0491 into mikelodder7:main Mar 11, 2025
9 checks passed
@mplanchard mplanchard deleted the const-country-fns branch March 11, 2025 14:39
@djc djc mentioned this pull request Mar 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants