arref/lib.rs
1//! Getting mutable references to two elements from the same array is hard.
2//! This tiny lib provides method to make it easier.
3//!
4//! [array_mut_ref!] checks whether the user borrows the same element at runtime.
5//!
6//! ```rust
7//! use arref::array_mut_ref;
8//! let mut arr = vec![1, 2, 3, 4];
9//! let (a, b) = array_mut_ref!(&mut arr, [1, 2]);
10//! assert_eq!(*a, 2);
11//! assert_eq!(*b, 3);
12//! let (a, b, c) = array_mut_ref!(&mut arr, [1, 2, 0]);
13//! assert_eq!(*c, 1);
14//!
15//! // ⚠️ The following code will panic. Because we borrow the same element twice.
16//! // let (a, b) = array_mut_ref!(&mut arr, [1, 1]);
17//! ```
18//!
19//! Alternatively, you can use [mut_twice]. It won't panic if you borrow the same element twice.
20//! It'll return an `Err(&mut T)` instead.
21//!
22//! ```rust
23//! use arref::mut_twice;
24//! let mut arr = vec![1, 2, 3];
25//! let (a, b) = mut_twice(&mut arr, 1, 2).unwrap();
26//! assert_eq!(*a, 2);
27//! assert_eq!(*b, 3);
28//! let result = mut_twice(&mut arr, 1, 1);
29//! assert!(result.is_err());
30//! if let Err(v) = result {
31//! assert_eq!(*v, 2);
32//! }
33//! ```
34//!
35
36/// It checks whether borrowing the same element at runtime, if so it'll panic.
37///
38/// ```rust
39/// use arref::array_mut_ref;
40/// let mut arr = vec![1, 2, 3, 4];
41/// let (a, b) = array_mut_ref!(&mut arr, [1, 2]);
42/// assert_eq!(*a, 2);
43/// assert_eq!(*b, 3);
44/// let (a, b, c) = array_mut_ref!(&mut arr, [1, 2, 0]);
45/// assert_eq!(*c, 1);
46///
47/// // ⚠️ The following code will panic. Because we borrow the same element twice.
48/// // let (a, b) = array_mut_ref!(&mut arr, [1, 1]);
49/// ```
50#[macro_export]
51macro_rules! array_mut_ref {
52 ($arr:expr, [$a0:expr, $a1:expr]) => {{
53 arref::array_mut_ref($arr, $a0, $a1)
54 }};
55 ($arr:expr, [$a0:expr, $a1:expr, $a2:expr]) => {{
56 arref::array_mut_ref3($arr, $a0, $a1, $a2)
57 }};
58}
59
60/// Get mutable references to two elements from the array.
61///
62/// If a0 and a1 point to the same element, it will return Err(&mut T).
63/// ```rust
64/// use arref::mut_twice;
65/// let mut arr = vec![1, 2, 3];
66/// let (a, b) = mut_twice(&mut arr, 1, 2).unwrap();
67/// assert_eq!(*a, 2);
68/// assert_eq!(*b, 3);
69/// let result = mut_twice(&mut arr, 1, 1);
70/// assert!(result.is_err());
71/// if let Err(v) = result {
72/// assert_eq!(*v, 2);
73/// }
74/// ```
75#[inline]
76pub fn mut_twice<T>(arr: &mut [T], a0: usize, a1: usize) -> Result<(&mut T, &mut T), &mut T> {
77 if a0 == a1 {
78 Err(&mut arr[a0])
79 } else {
80 unsafe {
81 Ok((
82 &mut *(&mut arr[a0] as *mut _),
83 &mut *(&mut arr[a1] as *mut _),
84 ))
85 }
86 }
87}
88
89#[doc(hidden)]
90#[inline]
91pub fn array_mut_ref3<T>(
92 arr: &mut [T],
93 a0: usize,
94 a1: usize,
95 a2: usize,
96) -> (&mut T, &mut T, &mut T) {
97 assert!(a0 != a1 && a1 != a2 && a0 != a2);
98 // SAFETY: this is safe because we know there are not multiple mutable references to the same element
99 unsafe {
100 (
101 &mut *(&mut arr[a0] as *mut _),
102 &mut *(&mut arr[a1] as *mut _),
103 &mut *(&mut arr[a2] as *mut _),
104 )
105 }
106}
107
108#[doc(hidden)]
109#[inline]
110pub fn array_mut_ref<T>(arr: &mut [T], a0: usize, a1: usize) -> (&mut T, &mut T) {
111 assert!(a0 != a1);
112 // SAFETY: this is safe because we know a0 != a1
113 unsafe {
114 (
115 &mut *(&mut arr[a0] as *mut _),
116 &mut *(&mut arr[a1] as *mut _),
117 )
118 }
119}