Skip to content

Move IfNonEmpty trait to carbide-utils, migrate stuff to it#3482

Merged
kensimon merged 1 commit into
NVIDIA:mainfrom
kensimon:none-if-empty
Jul 14, 2026
Merged

Move IfNonEmpty trait to carbide-utils, migrate stuff to it#3482
kensimon merged 1 commit into
NVIDIA:mainfrom
kensimon:none-if-empty

Conversation

@kensimon

@kensimon kensimon commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

We've rewritten similar helper functions in a lot of places to convert empty strings (or Option::None) to None. Use the trait-based one (IfNonEmpty), rename it NoneIfEmpty, move it to carbide-utils, and migrate code to use it. (I needed this again in another branch and I was sick of writing it yet-another time.)

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

We've rewritten similar helper functions in a lot of places to convert
empty strings (or Option<String>::None) to None. Use the trait-based one
(IfNonEmpty), move it to carbide-utils, and migrate code to use it. (I
needed this again in another branch and I was sick of writing it
yet-another time.)
@kensimon kensimon requested a review from a team as a code owner July 14, 2026 14:58
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

A shared NoneIfEmpty trait is added for converting empty strings and collections to None. Existing manual empty-value checks are replaced across CLI, API, controller, RPC, health, firmware, and site-explorer paths.

Changes

Empty-value normalization

Layer / File(s) Summary
Shared utility and crate wiring
crates/utils/*, crates/dpf/Cargo.toml, crates/dpu-remediation/Cargo.toml, crates/rpc-utils/Cargo.toml
Adds and exports NoneIfEmpty, implements it for strings and collections, adds unit tests, and wires adopting crates to carbide-utils.
CLI, agent, and API normalization
crates/admin-cli/*, crates/agent/*, crates/api-core/*, crates/api-db/*, crates/api-model/*
Replaces local empty-string and empty-collection checks in parsing, validation, display, reconciliation, identity, and site-explorer model logic.
Service and controller normalization
crates/dpf/*, crates/dpu-remediation/*, crates/health/*, crates/machine-controller/*, crates/rack-controller/*
Normalizes optional interfaces, metadata, metrics, firmware artifact fields, RMS URLs, and endpoint hostnames with the shared helper.
RPC and display conversions
crates/rpc/*, crates/rpc-utils/*
Uses NoneIfEmpty for protobuf/model label values, MLX fields, expected-switch addresses, validation tags, and managed-host display fields; removes the local display helper.
Site, firmware, and switch paths
crates/site-explorer/*, crates/scout/*, crates/switch-controller/*
Treats blank serials, fallback MAC sources, URL segments, and switch hostnames as absent values.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the refactor: moving the non-empty helper into carbide-utils and migrating callers, despite the informal "stuff" wording.
Description check ✅ Passed The description is directly related to the change set and accurately describes the helper rename, relocation, and migration work.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
crates/utils/src/none_if_empty.rs (2)

20-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Repetitive impl boilerplate could be macro-generated.

All ten NoneIfEmpty impls follow one of two fixed shapes (if self.is_empty() {None} else {Some(self)} for owned/borrowed non-Option types, and empty-filtering for Option<_> wrappers). A small declarative macro could generate these pairs and reduce ~80 lines to a fraction of that, while keeping the public trait surface identical. Given the guideline to prefer simple, explicit code and to only introduce abstractions when justified, this is optional — the current form is easy to read and audit — but worth considering if more type families get added later.

As per coding guidelines, "Prefer simple, explicit Rust code over clever or heavily abstracted code; abstractions should be justified by a real requirement."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/utils/src/none_if_empty.rs` around lines 20 - 104, The requested
change is optional: keep the explicit NoneIfEmpty implementations unless
additional type families justify reducing duplication. If consolidating, use a
small declarative macro to generate the owned/borrowed and Option-wrapped
implementations while preserving the public NoneIfEmpty trait and all existing
empty-value behavior.

Source: Coding guidelines


26-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider unifying the Option<T> impls via .filter().

Option<String> (Line 30) and Option<&str> (Line 88) use .filter(|value| !value.is_empty()), while Option<Vec<T>> (Lines 45-49) and Option<HashMap<K, V>> (Lines 63-67) use a match with a guard for the same semantics. Option<&[T]> (Line 102) reverts back to .filter(). Unifying all five Option<_> impls to the .filter() form would remove the stylistic inconsistency without any behavioral change.

♻️ Proposed fix for consistency
 impl<T> NoneIfEmpty for Option<Vec<T>> {
     type Val = Vec<T>;
     fn none_if_empty(self) -> Option<Self::Val> {
-        match self {
-            None => None,
-            Some(v) if v.is_empty() => None,
-            Some(v) => Some(v),
-        }
+        self.filter(|v| !v.is_empty())
     }
 }
 
 impl<K, V> NoneIfEmpty for Option<HashMap<K, V>> {
     type Val = HashMap<K, V>;
     fn none_if_empty(self) -> Option<Self::Val> {
-        match self {
-            None => None,
-            Some(h) if h.is_empty() => None,
-            Some(h) => Some(h),
-        }
+        self.filter(|h| !h.is_empty())
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/utils/src/none_if_empty.rs` around lines 26 - 104, Unify the
Option-based implementations of NoneIfEmpty by updating none_if_empty in
Option<Vec<T>> and Option<HashMap<K, V>> to use the same filter-based pattern
already used by Option<String>, Option<&str>, and Option<&[T]>. Preserve the
existing behavior of returning None for absent or empty values and Some for
non-empty values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/utils/src/none_if_empty.rs`:
- Around line 20-104: The requested change is optional: keep the explicit
NoneIfEmpty implementations unless additional type families justify reducing
duplication. If consolidating, use a small declarative macro to generate the
owned/borrowed and Option-wrapped implementations while preserving the public
NoneIfEmpty trait and all existing empty-value behavior.
- Around line 26-104: Unify the Option-based implementations of NoneIfEmpty by
updating none_if_empty in Option<Vec<T>> and Option<HashMap<K, V>> to use the
same filter-based pattern already used by Option<String>, Option<&str>, and
Option<&[T]>. Preserve the existing behavior of returning None for absent or
empty values and Some for non-empty values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 06cc05b5-617b-42a5-89b8-fda8de8af302

📥 Commits

Reviewing files that changed from the base of the PR and between f5044bc and 8db1f9b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (48)
  • crates/admin-cli/src/machine/nvlink_info/cmd.rs
  • crates/admin-cli/src/managed_switch/show/cmd.rs
  • crates/admin-cli/src/site_explorer/get_report/cmd.rs
  • crates/admin-cli/src/sku/bulk_update_metadata/cmd.rs
  • crates/agent/src/astra_weave.rs
  • crates/agent/src/dpu/interface.rs
  • crates/agent/src/ethernet_virtualization.rs
  • crates/api-core/src/cfg/file.rs
  • crates/api-core/src/ethernet_virtualization.rs
  • crates/api-core/src/handlers/bmc_endpoint_explorer.rs
  • crates/api-core/src/handlers/component_manager.rs
  • crates/api-core/src/handlers/extension_service.rs
  • crates/api-core/src/handlers/machine_discovery.rs
  • crates/api-core/src/handlers/machine_identity.rs
  • crates/api-core/src/handlers/tenant_identity_config.rs
  • crates/api-core/src/machine_identity/token_exchange.rs
  • crates/api-core/src/setup.rs
  • crates/api-db/src/machine_validation_suites.rs
  • crates/api-model/src/instance/status/extension_service.rs
  • crates/api-model/src/machine_boot_interface.rs
  • crates/api-model/src/site_explorer/mod.rs
  • crates/dpf/Cargo.toml
  • crates/dpf/src/sdk.rs
  • crates/dpu-remediation/Cargo.toml
  • crates/dpu-remediation/src/remediation.rs
  • crates/health/src/collectors/nvue/gnmi/sample_processor.rs
  • crates/health/src/endpoint/sources.rs
  • crates/machine-controller/src/handler/firmware_artifact.rs
  • crates/rack-controller/src/fabric_manager.rs
  • crates/rack-controller/src/maintenance.rs
  • crates/rack-controller/src/nmx_certificate.rs
  • crates/rpc-utils/Cargo.toml
  • crates/rpc-utils/src/managed_host_display.rs
  • crates/rpc/src/libmlx.rs
  • crates/rpc/src/model/compute_allocation.rs
  • crates/rpc/src/model/expected_switch.rs
  • crates/rpc/src/model/instance_type.rs
  • crates/rpc/src/model/machine_validation.rs
  • crates/rpc/src/model/metadata.rs
  • crates/rpc/src/model/network_security_group.rs
  • crates/rpc/src/model/vpc.rs
  • crates/scout/src/firmware_upgrade.rs
  • crates/site-explorer/src/lib.rs
  • crates/site-explorer/src/machine_creator.rs
  • crates/switch-controller/src/endpoint.rs
  • crates/switch-controller/src/maintenance.rs
  • crates/utils/src/lib.rs
  • crates/utils/src/none_if_empty.rs

@kensimon kensimon enabled auto-merge (squash) July 14, 2026 15:21
@kensimon kensimon merged commit 0a337f9 into NVIDIA:main Jul 14, 2026
59 checks passed
@github-actions

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
boot-artifacts-aarch64 3 0 0 3 0 0
boot-artifacts-x86_64 3 0 0 3 0 0
forge-admin-cli-x86_64 259 13 30 78 7 131
machine-validation-runner 807 40 234 288 36 209
machine_validation 807 40 234 288 36 209
machine_validation-aarch64 807 40 234 288 36 209
nvmetal-carbide 807 40 234 288 36 209
TOTAL 3493 173 966 1236 151 967

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

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