harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

harm: Implement interesting methods for SBitValue - #45

Merged
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue
Nov 30, 2025
Merged

harm: Implement interesting methods for SBitValue#45
monoid merged 3 commits into
masterfrom
feat/larger-sbitvalue

Conversation

@monoid

@monoidmonoid commented Nov 30, 2025

Copy link
Copy Markdown
Owner
  • from_i64: sometimes unshifted value fits only i64 (for example, AdrpOffset implemented as an aligned SBitValue<19, 12>).
  • from_shifted: another way to construct such values.

Summary by CodeRabbit

  • New Features

    • Improved error reporting and display for unsupported bit values.
    • Added ways to construct signed bit values from 64-bit integers and from pre-shifted inputs, with alignment and overflow validation.
  • Tests

    • Expanded test coverage for the new constructors, including valid, invalid, large, negative, and unsupported scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@monoidmonoid self-assigned this Nov 30, 2025
@monoidmonoid added enhancement New feature or request harm The `harm` dynamic assembler labels Nov 30, 2025
@coderabbitai

coderabbitaiBot commented Nov 30, 2025

Copy link
Copy Markdown

Walkthrough

Added BitError::Unsupported, two public SBitValue constructors (from_shifted and new_i64), updated Display to handle the new error, and added tests covering valid and error scenarios for shifted values and i64 conversion.

Changes

Cohort / File(s)Summary
Bit error, constructors, display, and tests
harm/src/bits.rs
Added Unsupported variant to pub enum BitError; added pub const fn from_shifted(shifted_value: i32) -> Result<Self, BitError> and pub const fn new_i64(value: i64) -> Result<Self, BitError> on SBitValue; updated Display to handle Unsupported; added tests for valid/invalid shifted inputs, i64 conversion, overflow, negative inputs, and unsupported cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect overflow and boundary checks in new_i64.
  • Verify shift/alignment calculations and error paths in from_shifted.
  • Confirm Display formatting and that tests cover each error variant including Unsupported.

Poem

🐇 I hop through bytes and count each bit,

A new "Unsupported" I tuck where needed,
Two constructors sprout, precise and fit,
Tests nibble edges where errors seeded,
Tiny paws applaud the change completed.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 58.33% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change—implementing new methods for SBitValue—matching the changeset which adds from_shifted() and new_i64() constructors with supporting error handling and tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/larger-sbitvalue

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

177-202: DRY: Delegate to from_shifted() instead of duplicating logic.

Lines 189-201 duplicate the overflow checking logic from from_shifted(). After validating alignment and converting to i32, you can simply call Self::from_shifted(shifted_value).

 pub const fn new_i64(value: i64) -> Result<Self, BitError> {
let shifted_value64 = value >> ALIGN;
if value != shifted_value64 << ALIGN {
return Err(BitError::Alignment { align: ALIGN as _ });
}
// It would be nice to have a try_into here, but it's not const yet.
// https://github.com/rust-lang/rust/issues/143773
let shifted_value: i32 = if (shifted_value64 as i32 as i64) == shifted_value64 {
shifted_value64 as i32
} else {
return Err(BitError::Unsupported);
};
- // TODO comparing ranges may be cleaner, and produces exactly same code.- let upper_bits = i32::BITS - SIGNIFICANT_BITS;- let there_and_back_again = (shifted_value << upper_bits) >> upper_bits;- if shifted_value == there_and_back_again {- let mask = u32::MAX >> upper_bits;- let nested = (shifted_value as u32) & mask;- Ok(Self(nested))- } else {- Err(BitError::Overflow {- significant_bits: SIGNIFICANT_BITS as _,- align: ALIGN as _,- })- }+ Self::from_shifted(shifted_value)
}

376-419: Consider adding a test for the Unsupported error case.

The tests cover valid i64 inputs and overflow scenarios, but there's no test exercising the BitError::Unsupported path when the shifted i64 value exceeds i32 bounds.

#[test]fntest_sbitvalue_new_i64_unsupported(){// Shifted value exceeds i32::MAXlet large:i64 = (i32::MAXasi64 + 1) << 2;let res = SBitValue::<30,2>::new_i64(large);assert_eq!(res,Err(BitError::Unsupported));}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d65079 and cab1e4b.

📒 Files selected for processing (1)
  • harm/src/bits.rs (4 hunks)
🔇 Additional comments (2)
harm/src/bits.rs (2)

11-11: New error variant looks good.

The Unsupported variant appropriately captures the case where an i64 value's shifted representation exceeds i32 bounds. The display message is generic but sufficient.

Also applies to: 31-33


158-175: Clean extraction of overflow validation logic.

Refactoring to use from_shifted() improves code organization and enables direct construction from pre-shifted values as described in the PR objectives.

@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from cab1e4b to 6e7e402CompareNovember 30, 2025 20:01

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

11-11: LGTM - Consider a more descriptive error message.

The Unsupported variant works correctly. The message "Unsupported value" is quite generic; you could consider something like "Shifted value exceeds i32 range" to help users diagnose issues more quickly, though the current message is acceptable.

Also applies to: 31-33


409-416: Good test coverage - note on type configuration.

This test correctly verifies that new_i64 returns Unsupported when the shifted value exceeds i32 range.

Note: SBitValue<40, 0> would have issues if from_shifted were actually reached (the subtraction 32 - 40 in upper_bits would underflow). The test works because the error is returned before that code path, as the comment suggests. This is fine for testing the Unsupported path, but consider using a valid type configuration like SBitValue<31, 0> with a value like 1i64 << 31 to avoid any confusion.

 #[test]
fn test_sbitvalue_new_i64_unsupported() {
- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<40, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ // Test that values exceeding i32 range return Unsupported+ type S31 = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Does not fit into `i32`- let res = WideType::new_i64(large_value);+ let res = S31::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cab1e4b and 6e7e402.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

153-159: Good refactor to reduce duplication.

Extracting the shifted-value validation into from_shifted and having new delegate to it is a clean approach that avoids code duplication.


161-175: LGTM - Correct sign-extension validation.

The round-trip check using arithmetic shifts correctly validates that the value fits within the signed range of SIGNIFICANT_BITS. The masking logic properly extracts the significant bits.


177-190: LGTM - Correct i64-to-i32 range validation.

The round-trip cast (shifted_value64 as i32 as i64) == shifted_value64 is the correct idiom for checking lossless i64→i32 conversion in a const context. The comment explaining the lack of try_into due to const limitations is helpful.


364-407: Comprehensive test coverage for the new constructors.

The tests effectively cover:

  • Basic equivalence with new() for small values
  • Large positive values near the maximum
  • Negative value representation (-1 producing all-ones)
  • Boundary conditions for from_shifted

Well done on the thorough testing.

+ `from_i64`: sometimes unshifted value fits only `i64` (for example,
`AdrpOffset` implemented as an aligned `SBitValue<19, 12>`).
+ `from_shifted`: another way to construct such values.
@monoid
monoidforce-pushed the feat/larger-sbitvalue branch from 6e7e402 to 883261fCompareNovember 30, 2025 20:30

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
harm/src/bits.rs (1)

31-33: Consider a more descriptive error message.

The error message "Unsupported value" is quite generic. Since Unsupported is specifically used when the shifted value doesn't fit in i32 (as seen in new_i64), consider a more informative message like "Value exceeds i32 range after alignment shift" or similar.

 BitError::Unsupported => {
- write!(f, "Unsupported value")+ write!(f, "Value exceeds i32 range after alignment shift")
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e7e402 and 883261f.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (4)
harm/src/bits.rs (4)

158-159: LGTM! Clean refactoring.

The extraction of overflow checking logic into from_shifted improves code modularity and enables constructing SBitValue from pre-shifted values.


161-175: LGTM! Correct sign-extension check.

The method correctly validates that the shifted value fits within SIGNIFICANT_BITS using sign-extension. The mask logic properly isolates the lower bits for storage.


177-190: LGTM! Correct i64 handling with const-compatible conversion check.

The method properly validates alignment, uses a clever round-trip cast to check if the i64 value fits in i32 (since try_into isn't const-stable yet), and delegates overflow checking to from_shifted. The logic correctly handles the case where the total bit range (SIGNIFICANT_BITS + ALIGN) may exceed 32 bits while keeping the shifted value within i32 bounds.


364-408: Comprehensive test coverage.

The test suite thoroughly validates the new methods including basic functionality, alignment handling, large values, negative values, overflow conditions, and the unsupported case. The test assertions correctly verify the expected behavior and error conditions.

Comment threadharm/src/bits.rs
Comment on lines +409 to +416
#[test]
fn test_sbitvalue_new_i64_unsupported() {
// Actually, harm doesn't use wide types so wide.
type WideType = SBitValue<31, 0>;
let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.
let res = WideType::new_i64(large_value);
assert_eq!(res, Err(BitError::Unsupported));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify test comment.

The comment on line 411 states "Does not fit into i32, but would fit the WideType", but this isn't accurate. SBitValue<31, 0> has a range of -(1 << 30) to (1 << 30) - 1 (i.e., -1,073,741,824 to 1,073,741,823). The value 1 << 31 (2,147,483,648) exceeds this range as well. The test correctly validates the Unsupported error, but the comment may confuse readers about why this error occurs.

Consider updating the comment to clarify:

- // Actually, harm doesn't use wide types so wide.+ // Test case where the shifted value doesn't fit in i32.
type WideType = SBitValue<31, 0>;
- let large_value: i64 = 1 << 31; // Does not fit into `i32`, but would fit the `WideType`.+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
🤖 Prompt for AI Agents
In harm/src/bits.rs around lines 409 to 416, the test comment wrongly claims the
value "Does not fit into `i32`, but would fit the `WideType`"; update the
comment to state that SBitValue<31, 0> has signed range -(1<<30) to (1<<30)-1
and that 1 << 31 (2,147,483,648) exceeds that range, so the test correctly
expects Err(BitError::Unsupported); change the comment to this clearer
explanation and leave the test logic unchanged.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

409-416: Clarify the test comment.

The comment on line 411 ("Actually, harm doesn't use wide types so wide.") is incomplete and unclear. This issue was already flagged in a previous review.

As suggested in the previous review, consider updating to:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value doesn't fit in i32.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 883261f and 6b66e97.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🧰 Additional context used
🪛 GitHub Actions: Rust
harm/src/bits.rs

[error] 29-33: cargo fmt --check failed. Misformatted Rust code detected in bits.rs; the Shifted value formatting should be written as a multi-line write! invocation. Command: 'cargo fmt -- --check'.

🔇 Additional comments (5)
harm/src/bits.rs (5)

11-11: LGTM!

The new Unsupported error variant appropriately represents cases where the shifted value cannot fit in the i32 implementation type.


153-159: LGTM!

Good refactoring to delegate to from_shifted after alignment validation. This reduces code duplication and improves maintainability.


161-175: LGTM!

The sign-extension validation correctly handles both positive and negative shifted values, and the bit masking properly extracts the significant bits.


177-190: LGTM!

The double-cast technique (shifted_value64 as i32 as i64) == shifted_value64 correctly validates whether the i64 value fits in i32 range, and the comment appropriately explains why try_into can't be used in const context.


364-407: LGTM!

Comprehensive test coverage for both new_i64 and from_shifted methods, including valid cases, overflow scenarios, and edge cases with negative values and large positive values.

Comment threadharm/src/bits.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
harm/src/bits.rs (1)

412-419: Clarify the Unsupported test comment to describe why the error occurs

The test logic for test_sbitvalue_new_i64_unsupported is correct, but the current comment ("Actually, harm doesn't use wide types so wide.") is a bit opaque and doesn’t explain that the failure is due to the i64i32 narrowing guard rather than the SBitValue type itself.

Consider updating the comments to make the intent explicit, e.g.:

- // Actually, harm doesn't use wide types so wide.- type WideType = SBitValue<31, 0>;- let large_value: i64 = 1 << 31; // Does not fit into `i32`.+ // Test case where the shifted value is representable in the SBitValue type+ // but not in the intermediate i32 implementation type used by `new_i64`.+ type WideType = SBitValue<31, 0>;+ let large_value: i64 = 1 << 31; // Exceeds i32::MAX, triggering Unsupported error.

This makes it clear that BitError::Unsupported is specifically about the implementation-type limitation, not about the generic SBitValue range itself.

🧹 Nitpick comments (2)
harm/src/bits.rs (2)

155-162: SBitValue::new delegation and from_shifted semantics look correct; consider documenting the contract

Delegating new to from_shifted preserves the previous alignment check (value must round‑trip through >> ALIGN/<< ALIGN) and centralises the signed‑range + packing logic in one place, which is good.

Since from_shifted is pub const and does not re-check alignment, it might be worth adding a brief doc comment clarifying that:

  • shifted_value is expected to be pre-shifted by ALIGN bits (i.e. already aligned), and
  • this constructor only enforces that the value fits in SIGNIFICANT_BITS as a signed integer, returning Overflow otherwise.

That will help external callers avoid accidentally skipping the alignment invariant that new/new_i64 enforce.

Also applies to: 164-178


180-193: new_i64 narrowing logic is sound; optional doc + extra test could clarify intent

The new_i64 implementation mirrors new’s alignment check and the (shifted_value64 as i32 as i64) == shifted_value64 pattern correctly guards the const narrowing from i64 to i32 before delegating to from_shifted, which matches the intended “only if the shifted value fits in i32” contract.

Two optional follow-ups you might consider:

  • Add a doc comment explaining that BitError::Unsupported specifically means “shifted value cannot be represented in i32 for this implementation”, distinguishing it from Overflow and SignOutRange.
  • Add a dedicated test where value is an i64 that does fit into i32 but not into SIGNIFICANT_BITS (so new_i64 returns Overflow), to lock in that behaviour for the i64 constructor as well.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b66e97 and 7f19c95.

📒 Files selected for processing (1)
  • harm/src/bits.rs (5 hunks)
🔇 Additional comments (3)
harm/src/bits.rs (3)

7-12: BitError::Unsupported variant and Display arm are consistent with new usage

The new Unsupported variant cleanly separates “cannot be represented in implementation type” from overflow/alignment, and the corresponding Display message matches how new_i64 uses it, so this extension of the error surface looks coherent.

Also applies to: 31-36


367-389: new_i64 tests exercise the main success paths well

The three new_i64 tests together cover:

  • parity with new for a misaligned value,
  • a large positive value within the representable signed range after shifting, and
  • a negative value exercising sign extension and masking.

That gives good confidence that new_i64 behaves consistently with new and from_shifted on the success paths.


391-410: from_shifted valid/invalid tests match the signed-range behaviour

The from_shifted tests correctly validate that:

  • SBitValue::<5, 2>::from_shifted(15) (just below the sign bit) encodes to raw bits 0b01111, and
  • SBitValue::<5, 2>::from_shifted(1 << 4) (value using the sign bit as magnitude) triggers an Overflow with the expected significant_bits/align.

These align nicely with the sign-extension based range check in from_shifted.

@monoid
monoid merged commit 162b3c8 into masterNov 30, 2025
2 checks passed
@monoid
monoid deleted the feat/larger-sbitvalue branch November 30, 2025 21:13
@coderabbitaicoderabbitaiBot mentioned this pull request Dec 7, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestharmThe `harm` dynamic assembler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@monoid