Skip to content

Add list support to c-api#7944

Draft
bschoenmaeckers wants to merge 2 commits into
RustPython:mainfrom
bschoenmaeckers:c-api-list
Draft

Add list support to c-api#7944
bschoenmaeckers wants to merge 2 commits into
RustPython:mainfrom
bschoenmaeckers:c-api-list

Conversation

@bschoenmaeckers
Copy link
Copy Markdown
Contributor

@bschoenmaeckers bschoenmaeckers commented May 21, 2026

Summary by CodeRabbit

  • New Features
    • Added C API support for list objects: create lists, query size, access and modify elements, append, insert, and reverse lists from the C interface.
    • Added list type-check helpers and clearer index-error behavior for out-of-bounds reads vs. assignments.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

Adds a public listobject module and implements C-API list functions (New, Size, GetItemRef, SetItem, Append, Insert, Reverse) that operate inside the VM, downcast to RustPython lists, perform bounds-checked reads/mutations, and produce Python index errors on invalid indices.

Changes

C-API List Object Support

Layer / File(s) Summary
Module declaration and list helpers
crates/capi/src/lib.rs, crates/capi/src/listobject.rs
Module listobject is publicly exported; imports and PyList_Check/PyList_CheckExact helpers are defined.
List construction and query operations
crates/capi/src/listobject.rs
PyList_New creates a list with reserved capacity; PyList_Size returns length; PyList_GetItemRef retrieves items by index with bounds checking and returns index errors.
List mutation operations
crates/capi/src/listobject.rs
PyList_SetItem assigns items (includes capacity-based fill special-case), PyList_Append appends, PyList_Insert inserts with bounds checks, and PyList_Reverse reverses in place; functions return c_int status and use VM-created index errors on failures.
Unit tests (disabled)
crates/capi/src/listobject.rs
Disabled #[cfg(false)] PyO3 test module covering creation, replacement, bounds errors, append, insert, and reverse.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • youknowone
  • ShaharNaveh

Poem

🐇 I nibbled bytes and stitched a list so neat,
New, Size, Get, Set — each hop a small feat,
Append and Insert, then Reverse on repeat,
A tiny rabbit patch where C and VM greet,
Soft paws pushing items in tidy beat.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding C-API list support functions to the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
Contributor

@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: 2

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

Inline comments:
In `@crates/capi/src/listobject.rs`:
- Around line 13-15: PyList_New incorrectly uses Vec::with_capacity which leaves
length 0 and permits PyList_SetItem to append; change PyList_New to create a
vector with actual length size (e.g., resize with vm.ctx.none() or equivalent
placeholder) so the new list's logical length equals size, and validate size is
non-negative at the FFI boundary (return null/set error on negative). Update
PyList_SetItem to only replace elements when index < list.len() (do not grow
using capacity checks or append), and ensure it signals an IndexError on
out-of-range indices; reference the functions PyList_New and PyList_SetItem and
the list_mut.len()/resize behavior when making these changes.
- Around line 48-50: In PyList_SetItem, avoid casting a negative index to usize;
before the existing match on index - list_mut.len() as isize (and before using
list_mut[index as usize] = item), explicitly check if index < 0, set a Python
IndexError and return -1; keep the existing match logic for non-negative indices
and use list_mut and item as before so negative indexes no longer panic the
process.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 88eba30c-c001-4026-8c59-75a1d14d083e

📥 Commits

Reviewing files that changed from the base of the PR and between c845861 and dfe08a8.

📒 Files selected for processing (2)
  • crates/capi/src/lib.rs
  • crates/capi/src/listobject.rs

Comment thread crates/capi/src/listobject.rs
Comment thread crates/capi/src/listobject.rs
@bschoenmaeckers bschoenmaeckers marked this pull request as draft May 21, 2026 06:46
@bschoenmaeckers bschoenmaeckers marked this pull request as ready for review May 21, 2026 16:17
Copy link
Copy Markdown
Contributor

@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.

♻️ Duplicate comments (1)
crates/capi/src/listobject.rs (1)

13-15: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Guard negative sizes before casting to usize.

A negative size becomes a huge capacity request here. On an extern "C" boundary, that can turn a bad C input into a panic/abort path instead of a normal Python error/NULL return.

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

In `@crates/capi/src/listobject.rs` around lines 13 - 15, The function PyList_New
currently casts a signed size to usize causing huge capacity requests for
negative inputs; modify PyList_New to detect size < 0 and, inside the with_vm
closure, set a Python error on the VM (e.g. a ValueError/OverflowError) and
return a NULL pointer instead of calling vm.ctx.new_list; keep using with_vm and
vm.ctx.new_list for the normal non-negative path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@crates/capi/src/listobject.rs`:
- Around line 13-15: The function PyList_New currently casts a signed size to
usize causing huge capacity requests for negative inputs; modify PyList_New to
detect size < 0 and, inside the with_vm closure, set a Python error on the VM
(e.g. a ValueError/OverflowError) and return a NULL pointer instead of calling
vm.ctx.new_list; keep using with_vm and vm.ctx.new_list for the normal
non-negative path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bf0b5a3c-19af-48d2-9f28-e7960f14f138

📥 Commits

Reviewing files that changed from the base of the PR and between dfe08a8 and 1c76eba.

📒 Files selected for processing (1)
  • crates/capi/src/listobject.rs

Copy link
Copy Markdown
Contributor

@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.

Caution

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

⚠️ Outside diff range comments (1)
crates/capi/src/listobject.rs (1)

83-100: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix PyList_Insert to normalize index like CPython (never raise IndexError just because where is out of range).

crates/capi/src/listobject.rs currently checks if index as usize > vec.len() and then does vec.insert(index as _, item), which causes:

  • Any negative index to be cast to a huge usize and return IndexError (CPython instead adjusts where by adding n and clamps to 0)
  • Any index > len to return IndexError (CPython instead clamps where to len and inserts/appends)

Update the implementation to match CPython’s ins1 normalization (where += n when where < 0, clamp to 0; clamp where > n to n). Also update the disabled test_list_insert: it currently asserts list.insert(2, 3).is_err() on a length-1 list, but CPython would append successfully.

♻️ Suggested fix
 pub unsafe extern "C" fn PyList_Insert(
     list: *mut PyObject,
     index: isize,
     item: *mut PyObject,
 ) -> c_int {
     with_vm(|vm| {
         let list = unsafe { &*list }.try_downcast_ref::<PyList>(vm)?;
         let item = unsafe { &*item }.to_owned();
         let mut vec = list.borrow_vec_mut();
-        if index as usize > vec.len() {
-            Err(vm.new_index_error(format!("list index out of range: {index}")))
-        } else {
-            vec.insert(index as _, item);
-            Ok(())
-        }
+        let len = vec.len() as isize;
+        let where_ = if index < 0 {
+            (index + len).max(0) as usize
+        } else {
+            (index as usize).min(vec.len())
+        };
+        vec.insert(where_, item);
+        Ok(())
     })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/capi/src/listobject.rs` around lines 83 - 100, PyList_Insert currently
casts the signed index to usize and rejects out-of-range values; change it to
follow CPython's ins1 normalization: read n = vec.len() as isize, if index < 0
then index += n, if index < 0 set index = 0, if index > n set index = n, then
convert the final index to usize and call vec.insert(index as _, item) (do not
perform the initial index as usize check). Update the associated
test_list_insert expectation to accept inserting at index > len as appending
(i.e., not an Err).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@crates/capi/src/listobject.rs`:
- Around line 83-100: PyList_Insert currently casts the signed index to usize
and rejects out-of-range values; change it to follow CPython's ins1
normalization: read n = vec.len() as isize, if index < 0 then index += n, if
index < 0 set index = 0, if index > n set index = n, then convert the final
index to usize and call vec.insert(index as _, item) (do not perform the initial
index as usize check). Update the associated test_list_insert expectation to
accept inserting at index > len as appending (i.e., not an Err).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bee7970f-ea6d-42f6-9fdd-7d5b6ec75a40

📥 Commits

Reviewing files that changed from the base of the PR and between 1c76eba and 0f3361b.

📒 Files selected for processing (1)
  • crates/capi/src/listobject.rs

@bschoenmaeckers bschoenmaeckers marked this pull request as draft May 21, 2026 16:30
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