From b8ad20e0e218cba3e6f6360d2448f31b20f35453 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 11 Mar 2021 14:49:49 -0500 Subject: [PATCH 1/3] initial version --- text/0000-get-mut-refs.md | 237 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 text/0000-get-mut-refs.md diff --git a/text/0000-get-mut-refs.md b/text/0000-get-mut-refs.md new file mode 100644 index 00000000000..8e5ad2271a9 --- /dev/null +++ b/text/0000-get-mut-refs.md @@ -0,0 +1,237 @@ +- Feature Name: get-mut-refs +- Start Date: 2021-03-11 +- RFC PR: TBD +- Rust Issue: TBD + +# Definitions: + +- "child place(s)": similar in concept to a struct field but opaque to the borrow checker, examples being an array index or a hash map's entry. +- "dependant trait": a trait which abstracts over some requirement of another trait + +# Summary +[summary]: #summary + +Add a new trait and dependant unsafe trait which together abstract over the retrieval of multiple `&mut` to child places. +The normal trait would be added as part of the v1 prelude so that these functions are easy to find and use. + +Example: (assume the trait function is called `get_mut_refs`) +```rust +let place1: usize = ...; +let place2: usize = ...; // where place1 != place2 + +let mut x = [0, 1, 2, 3, 4]; + +if let Some([x1, x2]) = x.get_mut_refs([place1, place2]) { + swap(x1, x2); +} + +dgb!{x}; +``` + +# Motivation +[motivation]: #motivation + +This is currently something that is not possible to do in safe code in rust because the borrow checker doesn't know how to deal with indexing or other forms of child places. +This mechanism would provide a standard way for types to implement the retrieval of multiple `&mut` to child places. +Because this exposes a safe API it can be used by everyone easily and thus reduces the difficulty of wanting to get multiple `&mut` into data structures at arbitrary locations. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Two new traits are added the `core` called `GetMutRefs` and `GetMutRefsRawEntry`. +It is not needed to import `GetMutRefs` as it is part of the prelude. +Unless you are implementing `GetMutRefs` for your own type the it is not needed to worry about `GetMutRefsRawEntry`. + +Normally, when rust code uses the `IndexMut` or `BorrowMut` trait it borrows the whole owned value and returns a single `&mut`. +However, for some data structures, such as arrays and vectors, it is possible and sometimes desirable to get more than one `&mut` out. +This is because these data structures represent a managed collection of values which are logically (and from a memory safety point of view) disjoint from each other. + +This trait is the common way for a data structure to expose this disjoint nature of its child places. +When the `get_mut_refs` method is called it checks that all keys are valid and that none of the resulting `&mut` would violate the `&mut` contracts. +If either of those are false then `None` is returned. + +## Examples: + +### Individual Entries: + +```rust +let mut x = [0, 1, 2, 3, 4]; + +if let Some([x1, x2]) = x.get_mut_refs([0, 4]) { + swap(x1, x2); +} + +dgb!{x}; // [4, 1, 2, 3, 0] +``` + +### Ranges: + +```rust +let mut x = [0, 1, 2, 3, 4]; + +if let Some([l, r]) = x.get_mut_refs([..2, 2..]) { + dbg!{l}; // &mut [0, 1] + dbg!{r}; // &mut [2, 3, 4] +} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +## Traits: + +```rust +/// This trait is unsafe to implement because it is used in upholding the +/// safety guarantees of `GetMutRefs` +unsafe trait GetMutRefsRawEntry { + type Value; + + /// should return true if both `&self` and `other` "point" to the entry or + /// entries within a parent instance + fn would_overlap(&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 + /// `would_overlap` + unsafe fn to_entry<'a>(self) -> &'a mut Self::Value; +} + +trait GetMutRefs { + type RawEntry: GetMutRefsRawEntry; + + /// 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]> { + let mut arr: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for (key, place) in array::IntoIter::new(keys).zip(arr.iter_mut()) { + unsafe { + place.as_mut_ptr().write(self.get_mut_ptr(key)?); + } + } + + let arr: [Self::RawEntry; N] = unsafe { MaybeUninit::array_assume_init(arr) }; + + for (i, x) in arr.iter().enumerate() { + for (j, y) in arr.iter().enumerate() { + if i != j && x.would_overlap(y) { + return None; + } + } + } + + let mut res: [MaybeUninit<&'a mut Value>; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for (raw_entry, place) in array::IntoIter::new(arr).zip(res.iter_mut()) { + unsafe { + place.as_mut_ptr().write(raw_entry.to_entry()); + } + } + + unsafe { + Some(MaybeUninit::array_assume_init(res)) + } + } + + /// 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; +} +``` + +- The default implementation is present to make this feature easier for implementors to use. +- Because of the default implementation there is an `unsafe trait` to abstract over the type used for `RawEntry`. +- This allows for the easy adding of new impls. Such as both `usize` and `Range` for slices. +- `RawEntry` is also required to correctly handle ZSTs, because two different ZSTs of the same type can exist at the same memory address. +So it is necessary to have some way of differentiating between them. + +For example the following could be an implementation of this trait for arrays. +Even accounting for ZSTs: + +```rust +struct ArrayRawEntry { + start: NonNull, + offset: usize, +} + +unsafe impl GetMutRefsRawEntry for ArrayRawEntry { + type Value = T; + + fn would_overlap(&self, other: &Self) -> bool { + self.start == other.start && self.offset == other.offset + } + + unsafe fn to_entry<'a>(self) -> &'a mut Self::Value { + self.start + .as_ptr() + .add(self.offset) + .as_mut() + .expect("NonNull plus usize should be NonNull") + } +} + +impl GetMutRefs for [T; LENGTH] { + type RawEntry = ArrayRawEntry; + + fn get_mut_ptr<'a>(&'a mut self, key: usize) -> Option { + if key < self.len() { + Some(Self::RawEntry { + start: NonNull::new(self.as_mut_ptr())?, + offset: key, + }) + } else { + None + } + } +} +``` + + +# Drawbacks +[drawbacks]: #drawbacks + +1. This adds another trait to the standard library which could be a crate. +1. This adds another trait to the prelude (for visibility reasons) +1. This could in theory be implemented in some form by the borrow checker in the future and having these traits might lead some to question if that is needed. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +- `get_mut_refs` might panic instead of returning `None` like other indexing traits. +If this was the case then it might also be a good idea to have a `try_get_mut_refs` which returns `None` instead of panicking. +- Add some form of multiple disjoint (and arbitrary) child place borrowing in the language instead of on top of it. +- Add more specific array patterns into the language (specifying indices). + +# Prior art +[prior-art]: #prior-art + +This was discussed on [rust internals](https://internals.rust-lang.org/t/add-as-mut-ref-for-slice-or-array/14199/31). +It started as a way to transform just arrays into an array of borrows but was soon found that while that already basically exists, it does not allow for arbitrary "picking" because of the limitations of array pattern. +However, that doesn't really help with other types that will probably never get structural patterns against them (ie `HashMap`). + +This was sort of inspired by the [deferred borrows paper](https://cfallin.org/pubs/ecoop2020_defborrow.pdf). +This is not in fact a solution at all to the problems set out in that paper, but arguably a stepping stone. +This is because that paper points to a possible future where types can define what sort of deferred borrows they support. +Whereas in this feature types can define what sort of multiple child place borrows they support. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- The names of the traits +- The names of the functions + +# Future possibilities +[future-possibilities]: #future-possibilities From b7f7eaa5bdb58c5e0bde84164f8b470b20d744ab Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 15 Mar 2021 15:26:34 -0400 Subject: [PATCH 2/3] add comments about future possibilities, removed range references --- text/0000-get-mut-refs.md | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/text/0000-get-mut-refs.md b/text/0000-get-mut-refs.md index 8e5ad2271a9..9909a49ea5a 100644 --- a/text/0000-get-mut-refs.md +++ b/text/0000-get-mut-refs.md @@ -64,17 +64,6 @@ if let Some([x1, x2]) = x.get_mut_refs([0, 4]) { dgb!{x}; // [4, 1, 2, 3, 0] ``` -### Ranges: - -```rust -let mut x = [0, 1, 2, 3, 4]; - -if let Some([l, r]) = x.get_mut_refs([..2, 2..]) { - dbg!{l}; // &mut [0, 1] - dbg!{r}; // &mut [2, 3, 4] -} -``` - # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -154,7 +143,7 @@ trait GetMutRefs { - The default implementation is present to make this feature easier for implementors to use. - Because of the default implementation there is an `unsafe trait` to abstract over the type used for `RawEntry`. -- This allows for the easy adding of new impls. Such as both `usize` and `Range` for slices. +- This allows for the easy adding of new impls. - `RawEntry` is also required to correctly handle ZSTs, because two different ZSTs of the same type can exist at the same memory address. So it is necessary to have some way of differentiating between them. @@ -199,13 +188,13 @@ impl GetMutRefs for [T; LENGTH] { } ``` - # Drawbacks [drawbacks]: #drawbacks 1. This adds another trait to the standard library which could be a crate. 1. This adds another trait to the prelude (for visibility reasons) 1. This could in theory be implemented in some form by the borrow checker in the future and having these traits might lead some to question if that is needed. +1. Doesn't support ranges currently because each range is a different type and the return type would have to be between individual items (`&mut T`) and multiple items (`&mut [T]`). # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives @@ -214,6 +203,9 @@ impl GetMutRefs for [T; LENGTH] { If this was the case then it might also be a good idea to have a `try_get_mut_refs` which returns `None` instead of panicking. - Add some form of multiple disjoint (and arbitrary) child place borrowing in the language instead of on top of it. - Add more specific array patterns into the language (specifying indices). +Though this has been noted as not being something that is currently desired (non-`RangeFull` in patterns). +- Implement such functionality separately for all types with no trait backing. +This might be a good idea because the trait doesn't seem very helpful to begin with (it is rather complicated) and might not be useful to be able to abstract over types that can `get_mut_refs`. # Prior art [prior-art]: #prior-art @@ -227,11 +219,31 @@ This is not in fact a solution at all to the problems set out in that paper, but This is because that paper points to a possible future where types can define what sort of deferred borrows they support. Whereas in this feature types can define what sort of multiple child place borrows they support. +HashBrown has recently added a similar sort of API ([currently unstable](https://github.com/rust-lang/hashbrown/pull/239)). +Its API is slightly different as each element is returned as `Result<&mut T, UnavailableMutError>`. +This means that each element has to be checked by the caller as well. +That is a possible alternative to the API but makes the simple general case (all or nothing) much more difficult to use. +Perhaps supporting both would be useful as it doesn't add too much complexity. + # Unresolved questions [unresolved-questions]: #unresolved-questions - The names of the traits - The names of the functions +- Individual impls or a trait # Future possibilities [future-possibilities]: #future-possibilities + +Either individual impls or a trait backing, it seems reasonable to add support for range based child place slice borrowing. +However, because this involves at least 6 distinct types: +- [`Range`](https://doc.rust-lang.org/std/ops/struct.Range.html) +- [`RangeFrom`](https://doc.rust-lang.org/std/ops/struct.RangeFrom.html) +- [`RangeInclusive`](https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html) +- [`RangeTo`](https://doc.rust-lang.org/std/ops/struct.RangeTo.html) +- [`RangeToInclusive`](https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html) +- [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) + +It does't seem likely that this would be `trait` backed. +Instead would probably be macro implemented like the old array impls. +Until such time as Rust gains a variadic generics support (at the very least). From 3b5b03f71d7f6d222df174bd91d7015c7822f804 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Sat, 3 Apr 2021 20:00:45 -0400 Subject: [PATCH 3/3] Change to a default impl, switch name, fix spelling mistakes --- text/0000-get-mut-refs.md | 141 +++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/text/0000-get-mut-refs.md b/text/0000-get-mut-refs.md index 9909a49ea5a..e7c11c28ad3 100644 --- a/text/0000-get-mut-refs.md +++ b/text/0000-get-mut-refs.md @@ -1,4 +1,4 @@ -- Feature Name: get-mut-refs +- Feature Name: get-mut-many - Start Date: 2021-03-11 - RFC PR: TBD - Rust Issue: TBD @@ -14,18 +14,18 @@ Add a new trait and dependant unsafe trait which together abstract over the retrieval of multiple `&mut` to child places. The normal trait would be added as part of the v1 prelude so that these functions are easy to find and use. -Example: (assume the trait function is called `get_mut_refs`) +Example: (assume the trait function is called `get_mut_many`) ```rust let place1: usize = ...; let place2: usize = ...; // where place1 != place2 let mut x = [0, 1, 2, 3, 4]; -if let Some([x1, x2]) = x.get_mut_refs([place1, place2]) { +if let Some([x1, x2]) = x.get_mut_many([place1, place2]) { swap(x1, x2); } -dgb!{x}; +dbg!{x}; ``` # Motivation @@ -38,16 +38,19 @@ Because this exposes a safe API it can be used by everyone easily and thus reduc # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -Two new traits are added the `core` called `GetMutRefs` and `GetMutRefsRawEntry`. -It is not needed to import `GetMutRefs` as it is part of the prelude. -Unless you are implementing `GetMutRefs` for your own type the it is not needed to worry about `GetMutRefsRawEntry`. +Two new traits are added the `core` called `GetMutMany` and `GetMutManyRaw`. +It is not needed to import `GetMutMany` as it is part of the prelude. +There is a provided implementation of `GetMutMany` in terms of types that implement `GetMutManyRaw`. +It is then possible to implement either trait to get this functionality. +Unless there is a good reason to, it is recommended to implement `GetMutManyRaw`. +This is to reuse the `unsafe` code within the default implementation as much as possible. Normally, when rust code uses the `IndexMut` or `BorrowMut` trait it borrows the whole owned value and returns a single `&mut`. However, for some data structures, such as arrays and vectors, it is possible and sometimes desirable to get more than one `&mut` out. This is because these data structures represent a managed collection of values which are logically (and from a memory safety point of view) disjoint from each other. This trait is the common way for a data structure to expose this disjoint nature of its child places. -When the `get_mut_refs` method is called it checks that all keys are valid and that none of the resulting `&mut` would violate the `&mut` contracts. +When the `get_mut_many` method is called it checks that all keys are valid and that none of the resulting `&mut` would violate the `&mut` contracts. If either of those are false then `None` is returned. ## Examples: @@ -57,11 +60,11 @@ If either of those are false then `None` is returned. ```rust let mut x = [0, 1, 2, 3, 4]; -if let Some([x1, x2]) = x.get_mut_refs([0, 4]) { +if let Some([x1, x2]) = x.get_mut_many([0, 4]) { swap(x1, x2); } -dgb!{x}; // [4, 1, 2, 3, 0] +dbg!{x}; // [4, 1, 2, 3, 0] ``` # Reference-level explanation @@ -71,40 +74,57 @@ dgb!{x}; // [4, 1, 2, 3, 0] ```rust /// This trait is unsafe to implement because it is used in upholding the -/// safety guarantees of `GetMutRefs` -unsafe trait GetMutRefsRawEntry { +/// safety guarantees of `GetMutMany` +unsafe trait GetMutManyRaw { type Value; + type RawEntry; /// should return true if both `&self` and `other` "point" to the entry or /// entries within a parent instance - fn would_overlap(&self, other: &Self) -> bool; + fn would_overlap(&self, e1: &Self::RawEntry, e2: &Self::RawEntry) -> bool; /// convert the item into a reference /// - /// saftey: the resulting reference must not break any of the `&mut` + /// safety: 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 /// `would_overlap` - unsafe fn to_entry<'a>(self) -> &'a mut Self::Value; + unsafe fn entry_to_ref<'a>(*mut self, entry: Self::RawEntry) -> &'a mut Self::Value; + + /// 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_raw_entry<'a>(&'a mut self, key: Key) -> Option; } -trait GetMutRefs { - type RawEntry: GetMutRefsRawEntry; +trait GetMutMany { + type 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>( + fn get_mut_many<'a, const N: usize>( + &'a mut self, + keys: [Key; N] + ) -> Option<[&'a mut Self::Value; N]>; +} + +impl GetMutMany for T +where + T: GetMutRefsRaw + >::Value = Value +{ + type Value = Value; + + fn get_mut_many<'a, const N: usize>( &'a mut self, keys: [Key; N] - ) -> Option<[&'a mut Value; N]> { + ) -> Option<[&'a mut Self::Value; N]> { let mut arr: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; for (key, place) in array::IntoIter::new(keys).zip(arr.iter_mut()) { unsafe { - place.as_mut_ptr().write(self.get_mut_ptr(key)?); + place.as_mut_ptr().write(self.get_raw_entry(key)?); } } @@ -112,17 +132,17 @@ trait GetMutRefs { for (i, x) in arr.iter().enumerate() { for (j, y) in arr.iter().enumerate() { - if i != j && x.would_overlap(y) { + if i != j && self.would_overlap(x, y) { return None; } } } - let mut res: [MaybeUninit<&'a mut Value>; N] = unsafe { MaybeUninit::uninit().assume_init() }; + let mut res: [MaybeUninit<&'a mut Self::Value>; N] = unsafe { MaybeUninit::uninit().assume_init() }; for (raw_entry, place) in array::IntoIter::new(arr).zip(res.iter_mut()) { unsafe { - place.as_mut_ptr().write(raw_entry.to_entry()); + place.as_mut_ptr().write((self as *mut T).entry_to_ref(raw_entry)); } } @@ -130,18 +150,10 @@ trait GetMutRefs { Some(MaybeUninit::array_assume_init(res)) } } - - /// 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; } ``` -- The default implementation is present to make this feature easier for implementors to use. +- The default implementation is present to make this feature easier for implementers to use. - Because of the default implementation there is an `unsafe trait` to abstract over the type used for `RawEntry`. - This allows for the easy adding of new impls. - `RawEntry` is also required to correctly handle ZSTs, because two different ZSTs of the same type can exist at the same memory address. @@ -152,33 +164,25 @@ Even accounting for ZSTs: ```rust struct ArrayRawEntry { - start: NonNull, offset: usize, } -unsafe impl GetMutRefsRawEntry for ArrayRawEntry { +unsafe impl GetMutManyRaw for [T; LENGTH] { type Value = T; - fn would_overlap(&self, other: &Self) -> bool { - self.start == other.start && self.offset == other.offset + fn would_overlap(&self, e1: &Self::RawEntry, e2: &Self::RawEntry) -> bool { + e1.offset == e2.offset } - unsafe fn to_entry<'a>(self) -> &'a mut Self::Value { - self.start - .as_ptr() - .add(self.offset) + unsafe fn entry_to_ref<'a>(*mut self, entry: Self::RawEntry) -> &'a mut Self::Value { + self.add(self.offset) .as_mut() .expect("NonNull plus usize should be NonNull") } -} - -impl GetMutRefs for [T; LENGTH] { - type RawEntry = ArrayRawEntry; - fn get_mut_ptr<'a>(&'a mut self, key: usize) -> Option { + fn get_raw_entry<'a>(&'a mut self, key: usize) -> Option { if key < self.len() { Some(Self::RawEntry { - start: NonNull::new(self.as_mut_ptr())?, offset: key, }) } else { @@ -188,24 +192,51 @@ impl GetMutRefs for [T; LENGTH] { } ``` +This second examples will be for the `BTreeMap` type. +Since this type works over user defined types (for its keys) this example shows the validity of the unsafe code in the default impl. + +```rust +unsafe impl GetMutManyRaw for Handle> { + type Value = T; + + fn would_overlap(&self, e1: &Self::RawEntry, e2: &Self::RawEntry) -> bool { + e1.eq(e2) + } + + unsafe fn entry_to_ref<'a>(*mut self, entry: Self::RawEntry) -> &'a mut Self::Value { + entry.into_val_mut() + } + + fn get_raw_entry<'a>(&'a mut self, key: K) -> Option { + let root_node = self.root.as_ref()?.borrow_mut(); + match root_node.search_tree(key) { + Found(handle) => Some(handle), + GoDown(_) => None, + } + } +} +``` + # Drawbacks [drawbacks]: #drawbacks 1. This adds another trait to the standard library which could be a crate. -1. This adds another trait to the prelude (for visibility reasons) -1. This could in theory be implemented in some form by the borrow checker in the future and having these traits might lead some to question if that is needed. -1. Doesn't support ranges currently because each range is a different type and the return type would have to be between individual items (`&mut T`) and multiple items (`&mut [T]`). +2. This adds another trait to the prelude (for visibility reasons) +3. This could in theory be implemented in some form by the borrow checker in the future and having these traits might lead some to question if that is needed. +4. Doesn't support ranges currently because each range is a different type and the return type would have to be between individual items (`&mut T`) and multiple items (`&mut [T]`). # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -- `get_mut_refs` might panic instead of returning `None` like other indexing traits. -If this was the case then it might also be a good idea to have a `try_get_mut_refs` which returns `None` instead of panicking. +- `get_mut_many` might panic instead of returning `None` like other indexing traits. +If this was the case then it might also be a good idea to have a `try_get_mut_many` which returns `None` instead of panicking. - Add some form of multiple disjoint (and arbitrary) child place borrowing in the language instead of on top of it. - Add more specific array patterns into the language (specifying indices). Though this has been noted as not being something that is currently desired (non-`RangeFull` in patterns). - Implement such functionality separately for all types with no trait backing. -This might be a good idea because the trait doesn't seem very helpful to begin with (it is rather complicated) and might not be useful to be able to abstract over types that can `get_mut_refs`. +This might be a good idea because the trait doesn't seem very helpful to begin with (it is rather complicated) and might not be useful to be able to abstract over types that can `get_mut_many`. +- A different name, more in line with the other indexing operational traits might be better, for instance something like `IndexMutMany`. +However, since this RFC is not proposing augmenting the indexing syntax that might get a bit confusing. # Prior art [prior-art]: #prior-art @@ -244,6 +275,6 @@ However, because this involves at least 6 distinct types: - [`RangeToInclusive`](https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html) - [`usize`](https://doc.rust-lang.org/std/primitive.usize.html) -It does't seem likely that this would be `trait` backed. +It doesn't seem likely that this would be `trait` backed. Instead would probably be macro implemented like the old array impls. Until such time as Rust gains a variadic generics support (at the very least).