Skip to content

Changes to Rust options parsing to facilitate Pants NG#23050

Merged
benjyw merged 2 commits intopantsbuild:mainfrom
benjyw:rust_ng_changes
Feb 9, 2026
Merged

Changes to Rust options parsing to facilitate Pants NG#23050
benjyw merged 2 commits intopantsbuild:mainfrom
benjyw:rust_ng_changes

Conversation

@benjyw
Copy link
Contributor

@benjyw benjyw commented Jan 29, 2026

  • Allow passing a buildroot through to NativeOptionParser
  • Replace uses of HashMap with BTreeMap, to allow the relevant structs to implement Hash
  • Implement Eq and Hash on various structs, which in some cases has to be done manually. E.g., Config values are not naturally Eq because they can contain floats.
  • Support secure (sha256) hashing of config file contents.
  • Make some private symbols pub or pub(crate) so they can be used by ng code.
  • Change the config file name to pantsng_*.toml when running in "ng" mode.

@benjyw benjyw added the release-notes:not-required [CI] PR doesn't require mention in release notes label Jan 29, 2026
@benjyw benjyw requested a review from sureshjoshi January 29, 2026 16:27

// Value doesn't implement Eq and Hash because of floats, but in our case we can insist that
// NaN == NaN for config equality/hash purposes. For one thing, we don't meaningfully
// support NaN in config values (although we don't enforce that they don't appear).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although we don't enforce that they don't appear

Should we? Or at the very least debug assert it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but we're no worse off than before if we don't. You could put a NaN in pants.toml today.

We have few if any float-valued options though, I am almost inclined to get rid of them one day and just require integers.

&& a0
.iter()
.zip(a1.iter())
.all(|(v0, v1)| _eq_toml_value(v0, v1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self - all is short circuiting.

Value::Integer(i) => i.hash(state),
Value::Float(f) => state.write_u64(f.to_bits()),
Value::Boolean(b) => b.hash(state),
// We don't support datetime types in config, so we won't incur this to_string() cost
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It datetime not supported by convention? Or like, we don't parse them earlier in the pipe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have accessors for them, so if you tried to read a field with that value type at the TOML level you'd have to read it as a string and I'm not sure what would happen.

let has_provided_configs = config_sources.is_some();

let buildroot = buildroot.unwrap_or(BuildRoot::find()?);
let buildroot = match buildroot {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this change?

Also, probably should have been unwrap_or_else originally would be my guess?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To not incur the cost of BuildRoot::find when buildroot is Some(). Could also have done unwrap_or_else(), yeah. I can change if you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh but then propagating the Err case gets annoying. So that's why I did it this way.

.file_stem()
.unwrap()
.to_string_lossy()
.strip_prefix("pantsng_")
Copy link
Member

@sureshjoshi sureshjoshi Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These "tags" are the _42 or _arm64 or _42_arm64 kinda thing? Not what Pants currently refers to as tags? Or do the concepts get merged?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this would be a good time to enforce limits on how these are created - what permutations are allowed, underscore vs dots, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, these are unrelated to those tags, but will likely supersede them.

Currently you can't specify your own tags, there are just a predetermined set of them based on OS, arch etc. But you're right that this needs to be made rigorous before allowing user tags.

hasher.update(k.as_bytes());
for v in vals {
if let Some(v) = v {
hasher.update(b"Some");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of adding this to the hash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the case when the bytes happen to spell None... Gotta be explicit.

Copy link
Member

@sureshjoshi sureshjoshi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments for my own sake, or just clarifying intent.

Since this is still in-prog, I didn't want to go down the rabbit hole of some of the memory/performance/error impacts (e.g. Arc<Mutex<... in a few places).

Also, my general rule of thumb to show intent is that most of my unwrap() are expect with the message for easier debugging when I crash with them.

@benjyw benjyw merged commit cfe3603 into pantsbuild:main Feb 9, 2026
47 of 50 checks passed
@benjyw benjyw deleted the rust_ng_changes branch February 9, 2026 02:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-notes:not-required [CI] PR doesn't require mention in release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants