Read tuple, bytes, int, float and complex payloads through views on Py<T> - #8819
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: RustPython/RustPython/.coderabbit.yml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughThe object API now exposes payload access for all types and limits implicit dereferencing to opted-in types. Tuple, list, and byte operations use borrowed slices or underlying data. Runtime access patterns changed across the C API, VM, standard library, derive code, and WebAssembly bindings. The summaries report existing behavior and checks as unchanged. ChangesPayload and Slice Access
Priority: ⬇️ Low Estimated code review effort: 4 (Complex) | ~60 minutes Merge Risk: ⚪ Minimal · up to This change primarily makes object and collection access explicit. No user-facing regression is established in the supplied review context, so the remaining merge risk is minimal. Architecture SummaryArchitecture risk: 🔵 Low · up to The change affects 1 system. Changed systems: Architecture concerns Review detailsSystems and components
Before / after behavior
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
f4f68a6 to
18d4764
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
9a62686 to
a4bd49b
Compare
179abf9 to
bb81feb
Compare
de5ddcd to
9639dde
Compare
- Add Py<PyTuple<R>>::as_slice(); it is generic over R, so typed tuples use the same view. - Callers reach slice methods, indexing and slice arguments through as_slice(). - PyTuple's own sequence and mapping slots and marshal's set_marshal_item reach the remaining PyTuple methods through the payload field. - The Py<T>::payload field is pub(crate). Assisted-by: Claude Code:claude-opus-5-5
- Callers read bytes through Py<PyBytes>::as_bytes(). - bytes.rs reaches PyBytesInner and the remaining PyBytes methods through the payload field; fspath and os call payload.contains_nuls(). - DictKey for [u8] falls back to the PyObject key_eq; it previously resolved to its own key_eq through Deref. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
…es() Assisted-by: Claude Code:claude-opus-5-5
Add `Py<PyInt>::as_bigint()`, `Py<PyInt>::try_to_primitive()` and `Py<PyFloat>::to_f64()`, which forward to the payload methods of the same name. Reads of the `value` field and primitive conversions go through these views; other PyInt and PyFloat methods are called through the `payload` field inside rustpython-vm and through payload() outside it. Assisted-by: Claude Code:claude-opus-5-5
Add Py<PyComplex>::as_complex() and use it at the call sites that read the payload directly. Assisted-by: Claude Code:claude-opus-5-5
try_to_i64_fast(), to_str_radix_10(), as_u32_mask(), as_u64_mask(), try_to_primitive() and try_to_primitive_raw() only read the integer value, so they are defined on Py<PyInt> and callers no longer go through the payload. PyRange computes its protocol length from the BigInt directly instead of building a PyInt payload. Assisted-by: Claude Code:claude-opus-5-5
… variant Py<PyInt>::try_to_primitive() and try_to_primitive_in_range(), renamed from try_to_primitive_raw(), both call to_primitive(). They differ only in how a negative value for an unsigned type is reported: ValueError for try_to_primitive(), OverflowError for try_to_primitive_in_range(). The target type is bound with `for<'a> TryFrom<&'a BigInt>`, so the methods no longer tie a lifetime to &self. Assisted-by: Claude Code:claude-opus-5-5
__xor__, __or__, __and__ and their int_op() helper are defined on Py<PyInt>. PyBool calls them without going through the payload. Assisted-by: Claude Code:claude-opus-5-5
__add__, __contains__, __getitem__ and __mod__ are defined on Py<PyBytes>. The subscript, contains and remainder slots call them without going through the payload. Assisted-by: Claude Code:claude-opus-5-5
The power slot calls them on Py<PyInt> without going through the payload. Assisted-by: Claude Code:claude-opus-5-5
9639dde to
e92674f
Compare
Follow-up to #8812.
Payload reads for tuple, bytes, int, float and complex go through explicit views on
Py<T>instead ofDeref<Target = T>.Derefitself is unchanged here.Py<T>:Py<PyTuple<R>>::as_slice(), generic overRso typed tuples share itPy<PyBytes>::as_bytes()Py<PyInt>::as_bigint(),Py<PyFloat>::to_f64(),Py<PyComplex>::as_complex()try_to_primitive(),try_to_primitive_in_range(),as_u32_mask(),as_u64_mask(),to_str_radix_10(),try_to_i64_fast()) and the operators__xor__/__or__/__and__,general_op()andmodpow()are defined onPy<PyInt>instead of the payload. PyBytes operators (__add__,__contains__,__getitem__,__mod__) move toPy<PyBytes>the same way.try_to_primitive()andtry_to_primitive_in_range()(renamed fromtry_to_primitive_raw()) share one conversion and differ only in the error for a negative value to an unsigned type: ValueError (PyLong_AsUInt32and the unsigned argument converters) or OverflowError (PyLong_AsUnsignedLong,PyLong_AsSize_t). Behavior is unchanged.PyBytesInnerinbytes.rs,PyBytes::contains_nuls,PyTuple::set_marshal_item, the types' own sequence/mapping slots, ...) are called through thepayloadfield insiderustpython-vmand throughpayload()outside it.Py<T>::payloadispub(crate).DictKey for [u8]falls back to thePyObjectkey_eq. Its fallback previously resolved to its ownkey_eqthroughDeref.astconstants build float and complex objects with.into(); they previously went throughDerefand allocated a second object.range's sequence/mapping length converts theBigIntlength directly instead of building aPyIntpayload.🤖 Generated with Claude Code