Skip to content

Conversation

@JoeyBF
Copy link
Collaborator

@JoeyBF JoeyBF commented Nov 26, 2025

This decouples the method implementations from the actual struct contents, which makes it easier to refactor in the near future.

Summary by CodeRabbit

  • Refactor
    • Internal vector, slice, and mutable-slice data were encapsulated and converted to use accessor-based APIs for consistent access and construction.
    • Constructors and internal creation paths were consolidated for clearer initialization and safer mutation.
    • Iteration and arithmetic internals were aligned with the new accessors.
    • No observable behavioral changes for users; functionality remains the same.

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

@JoeyBF
Copy link
Collaborator Author

JoeyBF commented Dec 9, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

This PR encapsulates FqVector/FqSlice/FqSliceMut internals: internal fields were made private and replaced with public/internal accessor methods and new constructors; all usages across the vector module were updated to call accessors instead of accessing fields directly.

Changes

Cohort / File(s) Summary
Core struct definitions
ext/crates/fp/src/vector/inner.rs
Made fields private (fq, len, limbs, start, end) for FqVector, FqSlice, FqSliceMut; added from_raw_parts, public fq() and len() and internal accessors (limbs(), limbs_mut(), vec_mut(), len_mut(), start(), end(), into_limbs(), etc.).
FqVector implementation
ext/crates/fp/src/vector/impl_fqvector.rs
Replaced direct field access with accessor calls (self.fq(), self.len(), self.limbs(), self.limbs_mut(), self.vec_mut(), etc.); migrated constructors to from_raw_parts/accessor-based patterns; removed previous public fq() and len() methods.
FqSlice implementation
ext/crates/fp/src/vector/impl_fqslice.rs
Converted field reads to accessor calls (self.fq(), self.limbs(), self.start(), self.end()); updated slice construction and From<&FqVector> usage to call accessors/constructors. Removed prior public new where noted.
FqSliceMut implementation
ext/crates/fp/src/vector/impl_fqslicemut.rs
Replaced field access with accessors (self.fq(), self.limbs(), self.limbs_mut(), self.start(), self.end()), added local fq caching in hotspots, and updated sub-slice/mutation paths to use new FqSliceMut::new(...) internal constructor (old public constructor removed).
Helpers / wrappers
ext/crates/fp/src/vector/fp_wrapper/helpers.rs
Updated calls from self.fq.el(...) to self.fq().el(...) to use the accessor.
Iterators
ext/crates/fp/src/vector/iter.rs
Switched iterator internals to consume/access accessors (vec.into_limbs(), vec.fq(), vec.start()) and adjusted derived calculations (bit_length, entries_per_limb, limb_bit_index_pair) to use fq() accessor results.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hid the limbs and closed the crate,
Accessors whisper through the gate.
No peeking fields, just tidy calls—
Hop, encapsulate, and mend the walls! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.51% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately reflects the primary change: making vector attributes private by removing pub(super) visibility from FqVector, FqSlice, and FqSliceMut struct fields.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 443fedc and fbd2dd9.

📒 Files selected for processing (6)
  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs
  • ext/crates/fp/src/vector/impl_fqslice.rs
  • ext/crates/fp/src/vector/impl_fqslicemut.rs
  • ext/crates/fp/src/vector/impl_fqvector.rs
  • ext/crates/fp/src/vector/inner.rs
  • ext/crates/fp/src/vector/iter.rs
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-12-11T08:35:31.031Z
Learnt from: JoeyBF
Repo: SpectralSequences/sseq PR: 205
File: ext/crates/fp/src/limb.rs:11-28
Timestamp: 2025-12-11T08:35:31.031Z
Learning: In Rust 2024 edition (Cargo.toml edition = 2024), the mem::size_of, size_of_val, align_of, and align_of_val functions from std::mem are in the prelude and do not require explicit imports. During reviews, these can be used unqualified when the project targets edition = 2024. Verify the crate's Cargo.toml edition setting before assuming unqualified use, and avoid adding extraneous imports for these helpers.

Applied to files:

  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs
  • ext/crates/fp/src/vector/impl_fqvector.rs
  • ext/crates/fp/src/vector/iter.rs
  • ext/crates/fp/src/vector/impl_fqslicemut.rs
  • ext/crates/fp/src/vector/inner.rs
  • ext/crates/fp/src/vector/impl_fqslice.rs
📚 Learning: 2025-12-14T08:23:53.399Z
Learnt from: JoeyBF
Repo: SpectralSequences/sseq PR: 207
File: ext/crates/fp/src/simd/x86_64/avx512.rs:367-379
Timestamp: 2025-12-14T08:23:53.399Z
Learning: In Rust 2024 edition, do not remove explicit unsafe blocks inside unsafe fn bodies. The lint unsafe_op_in_unsafe_fn is enabled by default, treating the body of an unsafe fn as safe and requiring each unsafe operation to be wrapped in an explicit unsafe { ... } block. Do not suggest removing these blocks in code using edition = "2024"; ensure unsafe operations are enclosed in explicit unsafe blocks and review for unnecessary nesting.

Applied to files:

  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs
  • ext/crates/fp/src/vector/impl_fqvector.rs
  • ext/crates/fp/src/vector/iter.rs
  • ext/crates/fp/src/vector/impl_fqslicemut.rs
  • ext/crates/fp/src/vector/inner.rs
  • ext/crates/fp/src/vector/impl_fqslice.rs
📚 Learning: 2025-12-15T22:15:17.779Z
Learnt from: JoeyBF
Repo: SpectralSequences/sseq PR: 207
File: ext/crates/fp/benches/mul.rs:19-28
Timestamp: 2025-12-15T22:15:17.779Z
Learning: In the fp crate, matrices over F_2 (prime=2) are stored with 1 bit per matrix entry. This means an M×N matrix uses M*N bits, i.e. M*N/8 bytes. For example, an 8192×8192 F_2 matrix uses (8192*8192)/8 = 8,388,608 bytes = 8 MB. Use this packing assumption when analyzing memory usage and bench tests, and rely on the crate's API for bit-packed access rather than byte-per-entry storage.

Applied to files:

  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs
  • ext/crates/fp/src/vector/impl_fqvector.rs
  • ext/crates/fp/src/vector/iter.rs
  • ext/crates/fp/src/vector/impl_fqslicemut.rs
  • ext/crates/fp/src/vector/inner.rs
  • ext/crates/fp/src/vector/impl_fqslice.rs
📚 Learning: 2025-12-20T04:55:22.617Z
Learnt from: JoeyBF
Repo: SpectralSequences/sseq PR: 207
File: ext/crates/fp/src/matrix/matrix_inner.rs:75-89
Timestamp: 2025-12-20T04:55:22.617Z
Learning: In reviews of code under ext/crates/fp/, treat AVec::from_iter(0, data) as using AVec's default alignment, not 0-byte alignment. Do not assume a reduced alignment or override of AVec's inherent alignment guarantees. If code relies on a specific alignment, verify it via AVec's type alias and its documentation, and avoid making changes that could alter alignment semantics. Ensure tests or comments reflect that 0 is a default alignment flag and not a zero-byte alignment.

Applied to files:

  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs
  • ext/crates/fp/src/vector/impl_fqvector.rs
  • ext/crates/fp/src/vector/iter.rs
  • ext/crates/fp/src/vector/impl_fqslicemut.rs
  • ext/crates/fp/src/vector/inner.rs
  • ext/crates/fp/src/vector/impl_fqslice.rs
🧬 Code graph analysis (5)
ext/crates/fp/src/vector/fp_wrapper/helpers.rs (1)
ext/crates/fp/src/vector/impl_fqslice.rs (1)
  • offset (110-114)
ext/crates/fp/src/vector/impl_fqvector.rs (4)
ext/crates/fp/src/vector/inner.rs (8)
  • from_raw_parts (46-49)
  • fq (51-53)
  • fq (86-88)
  • fq (117-119)
  • len (55-57)
  • limbs (59-61)
  • limbs (102-104)
  • limbs (133-135)
ext/crates/fp/src/vector/impl_fqslicemut.rs (1)
  • prime (14-16)
ext/crates/fp/src/field/field_internal.rs (3)
  • entries_per_limb (125-127)
  • bit_length (101-101)
  • bitmask (120-122)
ext/crates/fp/src/field/fp.rs (1)
  • bit_length (96-103)
ext/crates/fp/src/vector/iter.rs (1)
ext/crates/fp/src/vector/inner.rs (3)
  • limbs (59-61)
  • limbs (102-104)
  • limbs (133-135)
ext/crates/fp/src/vector/inner.rs (3)
ext/crates/fp/src/vector/impl_fqslice.rs (1)
  • len (21-23)
ext/crates/fp/src/vector/impl_fqvector.rs (1)
  • limbs (318-322)
ext/crates/fp/src/field/field_internal.rs (1)
  • number (168-174)
ext/crates/fp/src/vector/impl_fqslice.rs (1)
ext/crates/fp/src/vector/inner.rs (6)
  • new (77-84)
  • new (108-115)
  • start (94-96)
  • start (121-123)
  • end (98-100)
  • end (125-127)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test (beta)
  • GitHub Check: test (nightly)
  • GitHub Check: webserver (beta)
  • GitHub Check: test (stable)
  • GitHub Check: webserver (nightly)
  • GitHub Check: lint
  • GitHub Check: miri
🔇 Additional comments (25)
ext/crates/fp/src/vector/fp_wrapper/helpers.rs (2)

20-77: LGTM!

All helper methods correctly updated to use self.fq() accessor instead of direct field access. The changes are consistent and maintain the same semantics since F: Field implements Copy.


89-142: LGTM!

FqSliceMut helper methods correctly updated to use accessor-based API. The pattern is consistent with the FqVector helpers above.

ext/crates/fp/src/vector/iter.rs (2)

19-54: LGTM!

The iterator construction correctly uses the new accessor methods. Since FqSlice implements Copy, the into_limbs(self) call doesn't prevent subsequent uses of vec — the struct is implicitly copied. The accessor calls (fq(), start(), bitmask(), etc.) are consistent throughout.


127-158: LGTM!

FqVectorNonZeroIterator::new follows the same pattern as FqVectorIterator::new, correctly using accessor methods for field access.

ext/crates/fp/src/vector/impl_fqslice.rs (5)

16-27: LGTM!

Public methods prime(), len(), and is_empty() correctly updated to use accessor methods instead of direct field access.


29-42: LGTM!

The entry() method correctly chains accessor calls for bitmask, limb indexing, and decoding operations.


77-104: LGTM!

Both slice() and to_owned() correctly use the new FqSlice::new() constructor and accessor methods. The alignment check at line 93 uses self.start().is_multiple_of() appropriately.


107-142: LGTM!

Limb helper methods (offset(), limb_range(), limb_range_inner(), min_limb_mask(), max_limb_mask()) correctly updated to use accessor-based field access.


157-161: LGTM!

The From<&'a FqVector<F>> implementation correctly calls v.len() as a method rather than field access.

ext/crates/fp/src/vector/impl_fqvector.rs (6)

15-27: LGTM!

Constructors new() and new_with_capacity() correctly delegate to from_raw_parts(), centralizing the initialization logic.


43-72: LGTM!

I/O methods and slice accessors correctly updated to use limbs_mut(), self.fq(), self.len(), and self.limbs() accessors.


108-156: LGTM!

Mutation methods set_to_zero(), scale(), and add_offset() correctly use self.limbs_mut() for mutable access and self.fq() for field operations.


162-201: LGTM!

Assignment and resizing methods correctly use accessor patterns. The extend_len() and set_scratch_vector_size() methods appropriately use len_mut() and vec_mut() for direct vector manipulation.


203-296: LGTM!

Arithmetic operations (copy_from_slice, sign_rule, add_truncate, add_carry_limb, add_carry) correctly updated to use accessor-based field and limb access.


298-327: LGTM!

first_nonzero() and density() methods correctly use accessors for field properties and limb iteration.

ext/crates/fp/src/vector/impl_fqslicemut.rs (6)

13-50: LGTM!

Public methods prime(), add_basis_element(), set_entry(), and reduce_limbs() correctly updated to use accessor methods. The caching of fq in local variables (e.g., line 42) appropriately reduces repeated accessor calls in loops.


52-125: LGTM!

The scale(), set_to_zero(), and add() methods correctly use accessor-based patterns. Local caching of self.fq() at line 54 is a good practice for the multiple uses within the method.


186-201: LGTM!

The shl_assign() method correctly uses end_mut() for mutable access to the end index. The sequence of *self.end_mut() -= shift followed by self.fq().number(self.end()) correctly reads the updated value.


243-361: LGTM!

The add_shift_left() method and its nested AddShiftLeftData struct correctly use accessor methods for limb access. The helper methods within AddShiftLeftData use other.limbs() appropriately.


363-494: LGTM!

The add_shift_right() method follows the same pattern as add_shift_left(), correctly using accessor-based access throughout.


520-552: LGTM!

The slice_mut(), as_slice(), copy() methods and the From implementation correctly construct new slices using the FqSliceMut::new() and FqSlice::new() constructors with accessor-provided values.

ext/crates/fp/src/vector/inner.rs (4)

10-39: LGTM!

The fields are now properly encapsulated as private instead of pub(super). This achieves the PR's goal of decoupling method implementations from struct contents for easier future refactoring.


45-74: LGTM!

FqVector accessors are well-designed:

  • from_raw_parts, fq(), and len() are appropriately pub for external API usage
  • limbs(), limbs_mut(), vec_mut(), and len_mut() are pub(super) for internal module usage
  • The debug_assert in from_raw_parts validates the limbs length invariant
  • len() is correctly marked const

76-105: LGTM!

FqSlice accessors are correctly structured:

  • fq() is pub for external use
  • Constructor and internal accessors (new, into_limbs, start, end, limbs) are pub(super)
  • start() and end() are marked const for optimization
  • into_limbs(self) correctly returns the borrowed lifetime &'a [Limb]

107-140: LGTM!

FqSliceMut accessors mirror the FqSlice pattern appropriately:

  • fq() is pub for external use
  • All mutation accessors (end_mut(), limbs_mut()) are pub(super) to restrict modification to within the module

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ext/crates/fp/src/vector/impl_fqvector.rs (1)

63-82: Unsafe aliasing bug in to_bytes little‑endian branch

The change to compute num_limbs via self.fq().number(self.len()) is correct, but the existing unsafe block has a soundness issue:

unsafe {
    let buf: &[u8] =
        std::slice::from_raw_parts_mut(self.limbs().as_ptr() as *mut u8, num_bytes);
    buffer.write_all(buf)?;
}

Here self: &FqVector<_> and self.limbs() comes from an immutable reference, but from_raw_parts_mut creates a &mut [u8] alias to the same memory. Even though you immediately coerce to &[u8] and don’t write through it, creating a mutable reference aliased with an immutable one is UB in Rust.

You can fix this by using from_raw_parts on a *const u8 instead, which avoids introducing a &mut at all:

-        if cfg!(target_endian = "little") {
-            let num_bytes = num_limbs * size_of::<Limb>();
-            unsafe {
-                let buf: &[u8] =
-                    std::slice::from_raw_parts_mut(self.limbs().as_ptr() as *mut u8, num_bytes);
-                buffer.write_all(buf)?;
-            }
+        if cfg!(target_endian = "little") {
+            let num_bytes = num_limbs * size_of::<Limb>();
+            unsafe {
+                let buf: &[u8] =
+                    std::slice::from_raw_parts(self.limbs().as_ptr() as *const u8, num_bytes);
+                buffer.write_all(buf)?;
+            }

This keeps the layout assumptions but stays within Rust’s aliasing rules.

🧹 Nitpick comments (4)
ext/crates/fp/src/vector/impl_fqvector.rs (4)

43-61: update_from_bytes: accessor usage is fine; consider propagating I/O errors instead of unwrap

Switching to self.limbs_mut() is correct and keeps all mutation inside the accessor API. One thing to consider while you’re here: the little‑endian branch still uses read_exact(...).unwrap(), which will panic instead of returning an io::Error, unlike the big‑endian branch that uses ?. You can make behavior consistent and avoid unexpected panics by propagating the error:

-            unsafe {
-                let buf: &mut [u8] =
-                    std::slice::from_raw_parts_mut(limbs.as_mut_ptr() as *mut u8, num_bytes);
-                data.read_exact(buf).unwrap();
-            }
+            unsafe {
+                let buf: &mut [u8] =
+                    std::slice::from_raw_parts_mut(limbs.as_mut_ptr() as *mut u8, num_bytes);
+                data.read_exact(buf)?;
+            }

This keeps the API purely io::Result-based and avoids panics on read failures.


145-157: scale accessor migration looks correct; consider early return on zero scalar

The refactor to:

  • Assert self.fq() == c.field(),
  • Cache let fq = self.fq();, and
  • Use self.limbs_mut() in the loop

looks correct and preserves the prior behavior, including the special case for q = 2.

Minor optional tweak: when c == fq.zero(), you can return immediately after self.set_to_zero() to avoid running the second if fq.q() != 2 branch with a zero scalar:

-        if c == fq.zero() {
-            self.set_to_zero();
-        }
-        if fq.q() != 2 {
+        if c == fq.zero() {
+            self.set_to_zero();
+            return;
+        }
+        if fq.q() != 2 {

Not required, just a small clarity/perf improvement.


233-246: copy_from_slice correctly rebuilds limb storage via accessors

The updated implementation:

  • Asserts all slice elements share the same field as self.fq() and that lengths match.
  • Clears self.vec_mut() and repopulates it by chunking the slice into fq.entries_per_limb() pieces and fq.packing them.

This matches the representation used by constructors and keeps len unchanged (and still correct). If you ever want to shave a bit of repetition, you could bind let vec = self.vec_mut(); before clear/extend, but that’s optional.


288-337: add_carry_limb / add_carry accessor refactor maintains behavior; minor perf tidy‑up possible

The changes to:

  • Assert self.fq() == c.field() and self.fq() == other.fq(),
  • Use self.limbs() / self.limbs_mut() for carry propagation, and
  • Iterate up to self.limbs().len() in add_carry

all look correct and keep the previous algorithm intact.

If you want to avoid repeated self.fq() calls in the characteristic‑2 branch, you could cache it once:

-        assert_eq!(self.fq(), c.field());
-        if self.fq().q() == 2 {
-            let c = self.fq().encode(c);
+        assert_eq!(self.fq(), c.field());
+        let fq = self.fq();
+        if fq.q() == 2 {
+            let c = fq.encode(c);

Not necessary for correctness, just a small micro‑optimization/readability improvement.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 569ef6a and 443fedc.

📒 Files selected for processing (6)
  • ext/crates/fp/src/vector/fp_wrapper/helpers.rs (7 hunks)
  • ext/crates/fp/src/vector/impl_fqslice.rs (7 hunks)
  • ext/crates/fp/src/vector/impl_fqslicemut.rs (10 hunks)
  • ext/crates/fp/src/vector/impl_fqvector.rs (11 hunks)
  • ext/crates/fp/src/vector/inner.rs (2 hunks)
  • ext/crates/fp/src/vector/iter.rs (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
ext/crates/fp/src/vector/fp_wrapper/helpers.rs (1)
ext/crates/fp/src/vector/impl_fqslice.rs (1)
  • offset (106-110)
ext/crates/fp/src/vector/iter.rs (3)
ext/crates/fp/src/vector/inner.rs (3)
  • limbs (59-61)
  • limbs (102-104)
  • limbs (129-131)
ext/crates/fp/src/field/fp.rs (1)
  • bit_length (96-103)
ext/crates/fp/src/field/field_internal.rs (2)
  • bit_length (101-101)
  • entries_per_limb (125-127)
ext/crates/fp/src/vector/impl_fqslicemut.rs (2)
ext/crates/fp/src/vector/impl_fqvector.rs (4)
  • add_basis_element (116-119)
  • as_slice (106-108)
  • add (188-190)
  • new (16-20)
ext/crates/fp/src/vector/inner.rs (10)
  • fq (51-53)
  • fq (86-88)
  • fq (117-119)
  • len (55-57)
  • new (77-84)
  • new (108-115)
  • start (94-96)
  • start (121-123)
  • end (98-100)
  • end (125-127)
ext/crates/fp/src/vector/impl_fqvector.rs (1)
ext/crates/fp/src/vector/inner.rs (8)
  • from_raw_parts (46-49)
  • fq (51-53)
  • fq (86-88)
  • fq (117-119)
  • len (55-57)
  • limbs (59-61)
  • limbs (102-104)
  • limbs (129-131)
🔇 Additional comments (33)
ext/crates/fp/src/vector/inner.rs (4)

11-39: LGTM! The struct definitions correctly make all fields private, which is the core objective of this PR. This enforces encapsulation and will make future refactoring easier by ensuring all access goes through the accessor methods.


45-74: Accessors for FqVector are well-designed.

The accessor pattern is clean:

  • from_raw_parts includes a useful debug_assert to validate limb count
  • fq() and len() are public as they're part of the public API
  • limbs(), limbs_mut(), vec_mut(), and len_mut() are appropriately pub(super) for internal use

Note: len() is marked const which is correct, but fq() is not. This is fine since F: Field likely has non-const trait bounds.


76-105: FqSlice accessors look correct.

The into_limbs(self) method consumes self but since FqSlice implements Copy, this is a valid pattern that returns the borrowed lifetime 'a.

Minor note: start() and end() are marked const which is good for potential compile-time evaluation.


107-136: FqSliceMut accessors are consistent with FqSlice.

The implementation mirrors FqSlice appropriately, with the addition of limbs_mut() for mutable access. The start() and end() methods are not const here (unlike in FqSlice), but this is acceptable since mutable borrows are involved.

ext/crates/fp/src/vector/fp_wrapper/helpers.rs (2)

20-77: Consistent migration to accessor-based API for FqVector helpers.

All helper methods correctly updated from self.fq.el(...) to self.fq().el(...). The changes are mechanical and maintain identical functionality.


85-128: FqSliceMut helpers correctly updated.

All accessor usages are consistent with the pattern established in FqVector helpers.

ext/crates/fp/src/vector/iter.rs (2)

19-54: Iterator initialization correctly uses accessor methods.

The usage of vec.into_limbs() followed by vec.fq() and vec.start() works correctly because FqSlice implements Copy. Each accessor call operates on a copy of the slice.

The initialization logic properly handles the empty case (lines 24-36) and correctly calculates limb indices and entry positions.


127-158: FqVectorNonZeroIterator initialization follows the same correct pattern.

Consistent with FqVectorIterator, this implementation properly uses accessor methods and handles the empty case appropriately.

ext/crates/fp/src/vector/impl_fqslice.rs (5)

16-42: Public methods correctly updated to use accessors.

The implementations of prime(), len(), is_empty(), and entry() all properly use the new accessor methods. The is_empty() method correctly uses const accessors start() and end().


53-71: is_zero() correctly uses limbs() accessor for read access.

The method properly accesses limbs through self.limbs() for all range checks.


73-100: slice() and to_owned() properly construct new instances via accessors.

The slice() method uses FqSlice::new() with self.into_limbs() and correctly offsets start/end.

The to_owned() method efficiently handles the aligned case by copying limb ranges directly, using limbs() and limbs_mut() accessors appropriately.


103-150: Limb helper methods updated consistently.

All internal limb calculation methods (offset(), limb_range(), limb_masks(), etc.) correctly use accessors for field access.


153-157: From<&FqVector> implementation updated.

Uses v.len() method call instead of direct field access, consistent with the encapsulation goal.

ext/crates/fp/src/vector/impl_fqslicemut.rs (7)

13-50: Public methods correctly migrated to accessor pattern.

The prime(), add_basis_element(), set_entry(), and reduce_limbs() methods all properly use self.fq(), self.limbs(), and self.limbs_mut() accessors.

The local caching pattern (let fq = self.fq()) in reduce_limbs() (line 42) is a good practice to avoid repeated accessor calls in loops.


52-100: scale() and set_to_zero() correctly use accessor pattern.

Both methods properly use self.fq() and limb accessors. The local fq binding in scale() (line 54) optimizes repeated field access.


102-146: add() and add_tensor() properly validate field equality via accessors.

The assertions assert_eq!(self.fq(), c.field()) and assert_eq!(self.fq(), other.fq()) correctly use accessor methods for field comparison.


148-219: assign() and add_shift_none() correctly updated.

Both methods properly use accessor-based limb access. The add_shift_none() method caches fq locally (line 185) which is appropriate given the multiple fma_limb and reduce calls.


221-339: add_shift_left() implementation correctly uses accessors.

The AddShiftLeftData helper struct methods properly access other.limbs() for read-only limb access. The main method correctly uses self.fq() for field operations.


341-472: add_shift_right() mirrors add_shift_left() pattern correctly.

Consistent accessor usage throughout the helper struct and main method implementation.


474-530: Slice and conversion methods properly handle borrows with accessors.

The slice_mut() method (lines 498-508) correctly captures orig_start before calling self.limbs_mut(), avoiding borrow conflicts.

Similarly, copy() (lines 519-524) captures start and end before the mutable borrow, which is the correct pattern to avoid borrowing self while also taking self.limbs_mut().

The From<&mut FqVector> implementation correctly uses v.len() method.

ext/crates/fp/src/vector/impl_fqvector.rs (13)

16-27: Constructors via from_raw_parts maintain invariants and improve encapsulation

Using Self::from_raw_parts(fq, len, vec![0; number_of_limbs]) and the new_with_capacity path that resizes to fq.number(len) both respect the from_raw_parts invariant (limbs.len() == fq.number(len)) and centralize initialization in inner.rs. Looks correct and in line with the encapsulation goal.


84-90: is_empty and prime correctly leverage new accessors

Using self.len() in is_empty and self.fq().characteristic().to_dyn() in prime is a straightforward and correct migration away from direct field access.


92-102: Slice constructors correctly enforce bounds and use accessor‑based constructors

The updated slice/slice_mut:

  • Assert start <= end && end <= self.len(), guarding all index use.
  • Pass self.fq() and self.limbs() / self.limbs_mut() into FqSlice::new/FqSliceMut::new.

This keeps invariants local to the type and is consistent with the inner.rs accessor design.


116-128: Field consistency checks now go through fq() accessor

The assertions assert_eq!(self.fq(), value.field()); in add_basis_element and set_entry are semantically equivalent to the prior direct field checks and maintain the expected invariant that entries live in the same field as the vector.


138-143: set_to_zero correctly uses limbs_mut and preserves invariant about zero encoding

Looping over self.limbs_mut() and setting limbs to 0 matches the documented invariant that fq.encode(fq.zero()) is always zero, while keeping writes funneled through the accessor.


161-186: add_offset correctly uses accessors and respects limb offset logic

The updated assertions (self.fq(), other.fq(), self.len()) and the use of self.limbs_mut() / other.limbs() (including passing them into add_simd) preserve the original semantics. The min_limb computation and the skip(min_limb) zip over limbs still line up with offset / entries_per_limb().


192-207: assign and assign_partial refactor preserves invariants

  • assign now uses self.limbs_mut().copy_from_slice(other.limbs()), which is a direct and safe replacement for copying the raw limb buffer after asserting same field and length.
  • assign_partial copies only other.limbs().len() limbs, then zeroes the remainder via self.limbs_mut()[..].iter_mut(), correctly reusing existing capacity while ensuring trailing entries are zero.

Both keep the vector’s limb layout consistent with the existing len.


209-211: is_zero implementation is consistent with limb representation

Checking self.limbs().iter().all(|&x| x == 0) is an appropriate use of the new accessor and matches the representation invariant that zero vectors are all-zero limbs.


213-231: extend_len and set_scratch_vector_size maintain len/limbs consistency

Both methods:

  • Use self.len() / self.len_mut() instead of the raw field.
  • Compute new_len via self.fq().number(len) and resize the underlying vec_mut() with zeros.

This keeps the internal invariant limbs.len() == fq.number(len) in sync after resizing. Mutating len before/after resize is fine here since the whole operation holds an exclusive &mut self.


248-257: trim_start uses accessors and preserves limb/length invariant

The method:

  • Asserts n <= self.len() and that n is a multiple of entries_per_limb().
  • Computes num_limbs = n / entries_per.
  • Drains the first num_limbs limbs from self.vec_mut() and then subtracts n from *self.len_mut().

Given n is a multiple of entries per limb, the resulting len and limb count remain consistent with fq.number(len).


259-276: sign_rule accessor migration is straightforward

Swapping direct field access for self.fq() and self.limbs()/other.limbs() in sign_rule keeps the logic intact. The indices and loop bounds still align (0..self.limbs().len() with indexed access into both vectors).


278-286: add_truncate correctly uses accessors and preserves truncation semantics

Using self.fq() for fq, self.limbs_mut().iter_mut().zip_eq(other.limbs()), and then fq.truncate(*left)? preserves the existing semantics while routing all buffer access through accessors. The Option<()> behavior via ? is unchanged.


339-368: first_nonzero and density correctly use fq() and limb accessors

  • first_nonzero now pulls entries_per_limb, bit_length, and bitmask from self.fq() and scans self.limbs(); the index computation and decode call are unchanged.
  • density uses self.fq().q() to branch between bit counting (for q == 2) and iter_nonzero().count(), then divides by self.len().

Both functions are cleanly migrated to the accessor‑based API and preserve previous semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant