Re: [PATCH v3 1/2] rust: add projection infrastructure

From: Benno Lossin

Date: Mon Mar 02 2026 - 13:53:33 EST


On Mon Mar 2, 2026 at 3:49 PM CET, Gary Guo wrote:
> On Mon Mar 2, 2026 at 2:38 PM GMT, Benno Lossin wrote:
>> On Mon Mar 2, 2026 at 2:02 PM CET, Gary Guo wrote:
>>> +/// A helper trait to perform index projection.
>>> +///
>>> +/// This is similar to `core::slice::SliceIndex`, but operate on raw pointers safely and fallibly.
>>> +///
>>> +/// # Safety
>>> +///
>>> +/// `get` must return a pointer in bounds of the provided pointer.
>>
>> This only makes sense when the provided pointer already points at an
>> allocation. But since the functions of this trait aren't `unsafe`, it
>> must be sound to pass `ptr::null` to them.
>
> The "in bounds" here is the conceptual bounds of the pointer. So, for a pointer
> with size `x`, the address of the returned pointer lies between `ptr .. ptr +
> x`.

Okay, I haven't really seen that as a concept. Also, what is the size of
an invalid pointer?

>> I first thought that we might be able to just use `mem::size_of_val_raw`
>> [1] to give an upper and lower bound on the address of the returned
>> pointer, but that is unsafe and cannot be called with an arbitrary
>> pointer. Interestingly, `ptr::metadata` [2] can be called safely & with
>> any pointer; I would expect them to be very similar (except of course
>> for extern types).
>>
>> [1]: https://doc.rust-lang.org/std/mem/fn.size_of_val_raw.html
>> [2]: https://doc.rust-lang.org/std/ptr/fn.metadata.html
>
> I have a `KnownSize` trait for this in my I/O projection series that is
> implemented for `T: Sized` and `[T]`, and it returns the size when given a raw
> pointer.
>
>>
>> A pretty expensive solution would be to add a sealed trait `Indexable`
>> that we implement for all things that `T` is allowed to be; and then we
>> provide a safe function in that trait to query the maximum offset the
>> `get` function is allowed to make.
>>
>> Alternatively, we could use something like this:
>>
>> The implementation of `get` must:
>> - return a pointer obtained by offsetting the input pointer.
>> - ensure that when the input pointer points at a valid value of type
>> `T`, the offset must not be greater than [`mem::size_of_val_raw`]
>> of the input pointer.
>
> Given that I'm not introducing `KnownSize` trait in this patch, this is why I
> haven't used this kind of wording. Perhaps I can just bring `KnownSize` in early
> and use it first for documentation purpose only?

That sounds great.

>> Or something simpler that says "if the input pointer is valid, then
>> `get` must return a valid output pointer"?
>
> Hmm, wouldn't this give impression that "you can do whatever you want if the
> input pointer is not valid"?

Yes that's true, but why is that a problem?

>>> +#[diagnostic::on_unimplemented(message = "`{Self}` cannot be used to index `{T}`")]
>>> +#[doc(hidden)]
>>> +pub unsafe trait ProjectIndex<T: ?Sized>: Sized {
>>> + type Output: ?Sized;
>>> +
>>> + /// Returns an index-projected pointer, if in bounds.
>>> + fn get(self, slice: *mut T) -> Option<*mut Self::Output>;
>>
>> How about we name this `try_index` instead of the general `get`?
>
> I'm following the name on `SliceIndex`:
> https://doc.rust-lang.org/stable/std/slice/trait.SliceIndex.html.

Hmm, the methods in that trait are marked as unstable under
`slice_index_methods`, which doesn't have a tracking issue, so are
perma-unstable? I'll suggest the rename upstream as well.

Cheers,
Benno