Skip to content

Conversation

jswrenn
Copy link
Collaborator

@jswrenn jswrenn commented Mar 28, 2025

Previously, SplitAt's methods returned Option<(&(mut) Self, &(mut) Self::Trailing)>, where None reflects an index that's either out of bounds, or results in the split parts overlapping in a problematic manner. This design conflated two failure conditions into one and, worse, presented an overly expensive and conservative API: dynamically checking for overlap is expensive, and there are many cases in which overlapping parts are not problematic, and this API could not scale to accommodate them all.

SplitAt's methods now return Option<Split<&(mut) Self>>, where None reflects an out-of-bounds index, and Split<&(mut) Self> encodes the possibly-overlapping parts. Split<&(mut) Self> provides methods for producing references to the split parts via both dynamic overlap checking and via static bounds (e.g., Self: Immutable). This API is more both cheaper and more expressive.

This API is, in fact, slightly more expressive than is possible to demonstrate within zerocopy's current capabilities. Split::via_runtime_check is overly conservative when T: Immutable, but it is not currently possible to construct a DST which would have overlapping parts without T: Immutable. We intend to follow up with mechanisms for DST construction that don't have this limitation.

Makes progress towards #1290.

@joshlf
Copy link
Member

joshlf commented Mar 28, 2025

cc @kupiakos

Copy link
Member

@joshlf joshlf left a comment

Choose a reason for hiding this comment

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

🎉

src/split_at.rs Outdated
/// use zerocopy::{SplitAt, FromBytes};
/// # use zerocopy_derive::*;
///
/// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)]
Copy link
Member

Choose a reason for hiding this comment

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

Presumably you don't want to derive IntoBytes? As a consequence, you presumably don't need Packet to be generic over B?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's required by FromBytes::mut_from_bytes.

Copy link
Member

Choose a reason for hiding this comment

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

Ack. I wonder if this is a hint that users will ~never need this API lol. In particular, since slice DSTs are unsized, you can't ever construct one by value, and so the only way to construct a &mut MySliceDst is via reference transmute, but all of our support for reference transmutes requires Self: IntoBytes. I suppose you could have constructed one yourself (e.g. via unsized coercion), but it's certainly niche. Oh well.

Copy link
Collaborator Author

@jswrenn jswrenn Mar 29, 2025

Choose a reason for hiding this comment

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

A bunch of these look a little silly when situated right next to FromByte::ref_from_bytes (which requires Immutable) and FromBytes::mut_from_bytes (which requires IntoBytes), but I can see these being useful in generic contexts.

Copy link
Member

Choose a reason for hiding this comment

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

Example?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let's say you have a generic function that needs to split a dst that gets passed in. This function is generic over & and &mut references to a DST. Maybe you have some &mut DSTs that aren't Immutable, and some & DSTs that aren't IntoBytes. In such a case, a T: Unaligned bound might be the common denominator that lets you write this generic function.

Copy link
Contributor

@kupiakos kupiakos Mar 29, 2025

Choose a reason for hiding this comment

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

I see SplitAt as extending the toolkit of DST manipulation that's dependent on zerocopy traits and expertise to get right, towards a goal of working with them nearly as easily as sized structs. So I do generally support whatever flexible trait bounds are possible for converting, even though I don't have a "key use case" example either.

you can't ever construct one by value

I've been thinking that Box<Dst> construction could be done with a macro and struct init syntax. This'd fit well in zerocopy with the knowledge from KnownLayout/SplitAt.

Copy link
Member

Choose a reason for hiding this comment

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

In such a case, a T: Unaligned bound might be the common denominator that lets you write this generic function.

Sure, but this comment thread is about via_runtime_check, not about via_unaligned. My point is that, if you always need to have an IntoBytes bound anyway, then you may never actually need via_runtime_check.


To be clear, I still think we should keep via_runtime_check for completeness. I just think it's an interesting observation that we should think more about at some point.

Copy link
Member

Choose a reason for hiding this comment

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

I've been thinking that Box<Dst> construction could be done with a macro and struct init syntax. This'd fit well in zerocopy with the knowledge from KnownLayout/SplitAt.

Oh this could be really cool! If you have a prototype at some point, let us know! I could see adding this to zerocopy if it's a simple enough API (which I imagine it would be).

@jswrenn jswrenn force-pushed the split-errs branch 2 times, most recently from b8695e1 to b342e51 Compare March 29, 2025 11:44
@jswrenn jswrenn force-pushed the split-errs branch 4 times, most recently from fd5f6b5 to 9562f5e Compare March 29, 2025 14:35
@codecov-commenter
Copy link

codecov-commenter commented Mar 29, 2025

Codecov Report

Attention: Patch coverage is 89.68254% with 39 lines in your changes missing coverage. Please review.

Project coverage is 90.36%. Comparing base (7fdec6f) to head (93da72d).
Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
src/split_at.rs 89.68% 39 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2473      +/-   ##
==========================================
- Coverage   90.68%   90.36%   -0.33%     
==========================================
  Files          19       19              
  Lines        7712     7808      +96     
==========================================
+ Hits         6994     7056      +62     
- Misses        718      752      +34     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jswrenn jswrenn force-pushed the split-errs branch 4 times, most recently from 1bc06d1 to 57acb73 Compare March 29, 2025 16:10
@jswrenn jswrenn enabled auto-merge March 29, 2025 16:10
@jswrenn jswrenn requested a review from joshlf March 29, 2025 16:10
@jswrenn jswrenn force-pushed the split-errs branch 4 times, most recently from 708346e to c8a657d Compare April 2, 2025 19:04
@jswrenn jswrenn force-pushed the split-errs branch 4 times, most recently from d0d7cd0 to b21d06c Compare April 2, 2025 20:01
@jswrenn jswrenn requested a review from joshlf April 2, 2025 20:29
@joshlf joshlf requested a review from Copilot April 5, 2025 15:18
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 6 out of 9 changed files in this pull request and generated no comments.

Files not reviewed (3)
  • zerocopy-derive/tests/ui-msrv/struct.stderr: Language not supported
  • zerocopy-derive/tests/ui-nightly/struct.stderr: Language not supported
  • zerocopy-derive/tests/ui-stable/struct.stderr: Language not supported

@jswrenn jswrenn added this pull request to the merge queue Apr 7, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 7, 2025
By doing so, dynamic overlap checking can be avoided entirely in
many cases.

Makes progress towards #1290.
@jswrenn jswrenn enabled auto-merge April 7, 2025 22:26
@jswrenn jswrenn added this pull request to the merge queue Apr 7, 2025
Merged via the queue into main with commit 0709360 Apr 7, 2025
88 checks passed
@jswrenn jswrenn deleted the split-errs branch April 7, 2025 22:55
@joshlf joshlf mentioned this pull request Apr 8, 2025
6 tasks
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.

4 participants