# Add as\_mut\_ref for slice or array

**URL:** <https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199>\
**Category:** libs\
**Created:** [March 7, 2021, 8:27pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199 "2021-03-07T20:27:47Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 9, 2021, 7:05pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/21 "2021-03-09T19:05:41Z")

</div>

So this sounds like something that could be useful for rust's stdlib. Should I make a PR?

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [March 9, 2021, 7:16pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/22 "2021-03-09T19:16:02Z")

</div>

> [@CAD97](#):
>
> In which case checking address uniqueness as a proxy for disjoint `&mut` would be overly restrictive for ZST but not unsound.

I agree it wouldn't be unsound. But it'd mean that `.get_mut_multiple([0, 1])` on a slice of ZSTs would return an error, which feels incorrect.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 9, 2021, 7:36pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/23 "2021-03-09T19:36:19Z")

</div>

Would checking for duplicates be sound if we used `(*mut T, usize)`? Namely `|l, r| l.0 == r.0 && l.1 == r.1` for duplicates? That way should work even for ZSTs.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 9, 2021, 8:22pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/24 "2021-03-09T20:22:43Z")

</div>

The only reason to check the identity of the returned reference is that you can't trust keys in a generic context (e.g. `HashMap`) because `Eq` can't be trusted for correctness. For the specific case of a slice, it's enough to check that the indices are disjoint, since `usize` is a trusted language type and not a generic.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 9, 2021, 8:57pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/25 "2021-03-09T20:57:39Z")

</div>

True but I was thinking of a generic impl sort of like the following:

```rust
pub trait GetMutRefs<Key, Value> {
    /// Gets `N` mutable references to `Value`'s within `Self` if all the
    /// `keys` are valid and wouldn't result in overlapping `&mut`'s.
    ///
    /// This is default implented in terms of `get_single_mut_ptr`.
    fn get_mut_refs<'a, const N: usize>(
        &'a mut self,
        keys: [Key; N]
    ) -> Option<[&'a mut Value; N]> { ... }

    /// If `key` is not in `self` return None, otherwise return Some tuple 
    /// of the pointer to the start of the collection of Values and an 
    /// offset number of elements within. This is needed for ZSTs.
    fn get_mut_ptr<'a>(
        &'a mut self, 
        key: Key
    ) -> Option<(NonNull<Value>, usize)>;
}

```

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 9, 2021, 9:23pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/26 "2021-03-09T21:23:43Z")

</div>

Ah. Unfortunately getting that `usize` offset could be expensive for some data structures. Probably the better solution would be to instead of `(*mut T, usize)`, use some associated `Self::RawEntry` type that can check its identity against other raw entries and also retrieve the key pointer. Then e.g. a BTree can compare node identity and node index, rather than having to calculate the item index.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 10, 2021, 2:35am UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/27 "2021-03-10T02:35:29Z")

</div>

Ah that makes sense. Also TIL that associated types in traits can have bounds within the trait declaration.

So that makes the following a better basis I would imagine:

```rust
/// This trait is unsafe to implement because it is used in upholding the
/// safety guarantees of `GetMutRefs`
unsafe trait GetRefMutsRawEntry {
    type Value;

    /// should return true if both `&self` and `other` "point" to the entry
    fn eq_raw_entry(&self, other: &Self) -> bool;

    /// convert the item into a reference
    ///
    /// saftey: the resulting reference must not break any of the `&mut`
    /// rules. Namely if you have a collections of `Self`'s and mean to 
    /// call `to_entry()` on all of them. Then all distinct pairs in that 
    /// collection must return `false` from a theoretical call to 
    /// `eq_raw_entry`
    unsafe fn to_entry<'a>(self) -> &'a mut Value;
}

trait GetRefMuts<Key, Value> {
    type RawEntry: GetRefMutsRawEntry<Value = Value>;

    /// Gets `N` mutable references to `Value`'s within `Self` if all the
    /// `keys` are valid and wouldn't result in overlapping `&mut`'s.
    ///
    /// This is default implented in terms of `get_single_mut_ptr`.
    fn get_mut_refs<'a, const N: usize>(
        &'a mut self,
        keys: [Key; N]
    ) -> Option<[&'a mut Value; N]> { ... }

    /// If `key` is not in `self` return None, otherwise return Some tuple 
    /// of the pointer to the start of the collection of Values and an 
    /// offset number of elements within. This is needed for ZSTs.
    fn get_mut_ptr<'a>(
        &'a mut self, 
        key: Key
    ) -> Option<RawEntry>;
}

```

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 10, 2021, 6:02am UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/28 "2021-03-10T06:02:20Z")

</div>

One last thing is that reborrowing to call `get_mut_ptr` might end up invalidating previous raw entries. This is complicated and we'd need to see an actual impl to know for sure, I think.

But the general shape would work as far as I understand it, it's just details around handling provenance and ownership during the process, not the API we want to provide, that's under question still.

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 11, 2021, 4:32pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/29 "2021-03-11T16:32:02Z")

</div>

Would therefore a libs PR against the rust repo be the next step or an actual RFC?

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [March 11, 2021, 6:00pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/30 "2021-03-11T18:00:27Z")

</div>

Hard to say on this one. On one hand it's "just" a new API, for which a PR is fine, but it's also a "thing that if it's good sets a new convention that lots of things should do", where an RFC is often best. And there are some interesting design questions -- whether `.get_mut_multiple((..k, k+1..))` should work too, for example -- that also makes me lean RFC.

Maybe write up a proposal (not quite an RFC, but a standalone thing with the motivation and proposed API) and post it to [Zulip](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs) to see what T-libs thinks?

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [March 11, 2021, 6:15pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/31 "2021-03-11T18:15:01Z")

</div>

Sounds good thanks for the guidance. I'll start working on something in the vein of an RFC and post a link to the github rendered version to Zulip. Sound good.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [June 9, 2021, 6:15pm UTC](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/32 "2021-06-09T18:15:27Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

[Previous page](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199.md?page=1)
