ndarray/impl_ref_types.rs
1//! Implementations that connect arrays to their reference types.
2//!
3//! `ndarray` has four kinds of array types that users may interact with:
4//! 1. [`ArrayBase`], which represents arrays which own their layout (shape and strides)
5//! 2. [`ArrayRef`], which represents a read-safe, uniquely-owned look at an array
6//! 3. [`RawRef`], which represents a read-unsafe, possibly-shared look at an array
7//! 4. [`LayoutRef`], which represents a look at an array's underlying structure,
8//! but does not allow data reading of any kind
9//!
10//! These types are connected through a number of `Deref` and `AsRef` implementations.
11//! 1. `ArrayBase<S, D>` dereferences to `ArrayRef` when `S: Data`
12//! 2. `ArrayBase<S, D>` mutably dereferences to `ArrayRef` when `S: DataMut`, and ensures uniqueness
13//! 3. `ArrayRef` mutably dereferences to `RawRef`
14//! 4. `RawRef` mutably dereferences to `LayoutRef`
15//! This chain works very well for arrays whose data is safe to read and is uniquely held.
16//! Because raw views do not meet `S: Data`, they cannot dereference to `ArrayRef`; furthermore,
17//! technical limitations of Rust's compiler means that `ArrayBase` cannot have multiple `Deref` implementations.
18//! In addition, shared-data arrays do not want to go down the `Deref` path to get to methods on `RawRef`
19//! or `LayoutRef`, since that would unecessarily ensure their uniqueness.
20//!
21//! To mitigate these problems, `ndarray` also provides `AsRef` and `AsMut` implementations as follows:
22//! 1. `ArrayBase` implements `AsRef` to `RawRef` and `LayoutRef` when `S: RawData`
23//! 2. `ArrayBase` implements `AsMut` to `RawRef` when `S: RawDataMut`
24//! 3. `ArrayBase` implements `AsRef` and `AsMut` to `LayoutRef` unconditionally
25//! 4. `ArrayRef` implements `AsRef` and `AsMut` to `RawRef` and `LayoutRef` unconditionally
26//! 5. `RawRef` implements `AsRef` and `AsMut` to `LayoutRef`
27//! 6. `RawRef` and `LayoutRef` implement `AsRef` and `AsMut` to themselves
28//!
29//! This allows users to write a single method or trait implementation that takes `T: AsRef<RawRef<A, D>>`
30//! or `T: AsRef<LayoutRef<A, D>>` and have that functionality work on any of the relevant array types.
31
32use alloc::borrow::ToOwned;
33use core::{
34 borrow::{Borrow, BorrowMut},
35 ops::{Deref, DerefMut},
36};
37
38use crate::{
39 Array,
40 ArrayBase,
41 ArrayPartsSized,
42 ArrayPartsUnsized,
43 ArrayRef,
44 Data,
45 DataMut,
46 Dimension,
47 LayoutRef,
48 RawData,
49 RawDataMut,
50 RawRef,
51};
52
53// D1: &ArrayBase -> &ArrayRef when data is safe to read
54impl<S, D> Deref for ArrayBase<S, D>
55where S: Data
56{
57 type Target = ArrayRef<S::Elem, D>;
58
59 fn deref(&self) -> &Self::Target
60 {
61 // SAFETY:
62 // - The pointer is aligned because neither type uses repr(align)
63 // - It is "dereferencable" because it comes from a reference
64 // - For the same reason, it is initialized
65 // - The cast is valid because ArrayRef uses #[repr(transparent)]
66 let parts: &ArrayPartsUnsized<S::Elem, D> = &self.parts;
67 let ptr = (parts as *const ArrayPartsUnsized<S::Elem, D>) as *const ArrayRef<S::Elem, D>;
68 unsafe { &*ptr }
69 }
70}
71
72// D2: &mut ArrayBase -> &mut ArrayRef when data is safe to read; ensure uniqueness
73impl<S, D> DerefMut for ArrayBase<S, D>
74where
75 S: DataMut,
76 D: Dimension,
77{
78 fn deref_mut(&mut self) -> &mut Self::Target
79 {
80 self.ensure_unique();
81 // SAFETY:
82 // - The pointer is aligned because neither type uses repr(align)
83 // - It is "dereferencable" because it comes from a reference
84 // - For the same reason, it is initialized
85 // - The cast is valid because ArrayRef uses #[repr(transparent)]
86 let parts: &mut ArrayPartsUnsized<S::Elem, D> = &mut self.parts;
87 let ptr = (parts as *mut ArrayPartsUnsized<S::Elem, D>) as *mut ArrayRef<S::Elem, D>;
88 unsafe { &mut *ptr }
89 }
90}
91
92// D3: &ArrayRef -> &RawRef
93impl<A, D> Deref for ArrayRef<A, D>
94{
95 type Target = RawRef<A, D>;
96
97 fn deref(&self) -> &Self::Target
98 {
99 // SAFETY:
100 // - The pointer is aligned because neither type uses repr(align)
101 // - It is "dereferencable" because it comes from a reference
102 // - For the same reason, it is initialized
103 // - The cast is valid because ArrayRef uses #[repr(transparent)]
104 unsafe { &*((self as *const ArrayRef<A, D>) as *const RawRef<A, D>) }
105 }
106}
107
108// D4: &mut ArrayRef -> &mut RawRef
109impl<A, D> DerefMut for ArrayRef<A, D>
110{
111 fn deref_mut(&mut self) -> &mut Self::Target
112 {
113 // SAFETY:
114 // - The pointer is aligned because neither type uses repr(align)
115 // - It is "dereferencable" because it comes from a reference
116 // - For the same reason, it is initialized
117 // - The cast is valid because ArrayRef uses #[repr(transparent)]
118 unsafe { &mut *((self as *mut ArrayRef<A, D>) as *mut RawRef<A, D>) }
119 }
120}
121
122// D5: &RawRef -> &LayoutRef
123impl<A, D> Deref for RawRef<A, D>
124{
125 type Target = LayoutRef<A, D>;
126
127 fn deref(&self) -> &Self::Target
128 {
129 &self.0
130 }
131}
132
133// D5: &mut RawRef -> &mut LayoutRef
134impl<A, D> DerefMut for RawRef<A, D>
135{
136 fn deref_mut(&mut self) -> &mut Self::Target
137 {
138 &mut self.0
139 }
140}
141
142// A1: &ArrayBase -AR-> &RawRef
143impl<A, S, D> AsRef<RawRef<A, D>> for ArrayBase<S, D>
144where S: RawData<Elem = A>
145{
146 fn as_ref(&self) -> &RawRef<A, D>
147 {
148 // SAFETY:
149 // - The pointer is aligned because neither type uses repr(align)
150 // - It is "dereferencable" because it comes from a reference
151 // - For the same reason, it is initialized
152 // - The cast is valid because ArrayRef uses #[repr(transparent)]
153 let parts: &ArrayPartsUnsized<S::Elem, D> = &self.parts;
154 let ptr = (parts as *const ArrayPartsUnsized<S::Elem, D>) as *const RawRef<S::Elem, D>;
155 unsafe { &*ptr }
156 }
157}
158
159// A2: &mut ArrayBase -AM-> &mut RawRef
160impl<A, S, D> AsMut<RawRef<A, D>> for ArrayBase<S, D>
161where S: RawDataMut<Elem = A>
162{
163 fn as_mut(&mut self) -> &mut RawRef<A, D>
164 {
165 // SAFETY:
166 // - The pointer is aligned because neither type uses repr(align)
167 // - It is "dereferencable" because it comes from a reference
168 // - For the same reason, it is initialized
169 // - The cast is valid because ArrayRef uses #[repr(transparent)]
170 let parts: &mut ArrayPartsUnsized<S::Elem, D> = &mut self.parts;
171 let ptr = (parts as *mut ArrayPartsUnsized<S::Elem, D>) as *mut RawRef<S::Elem, D>;
172 unsafe { &mut *ptr }
173 }
174}
175
176// A3: &ArrayBase -AR-> &LayoutRef
177impl<A, S, D> AsRef<LayoutRef<A, D>> for ArrayBase<S, D>
178where S: RawData<Elem = A>
179{
180 fn as_ref(&self) -> &LayoutRef<A, D>
181 {
182 let parts: &ArrayPartsUnsized<S::Elem, D> = &self.parts;
183 let ptr = (parts as *const ArrayPartsUnsized<S::Elem, D>) as *const LayoutRef<S::Elem, D>;
184 unsafe { &*ptr }
185 }
186}
187
188// A3: &mut ArrayBase -AM-> &mut LayoutRef
189impl<A, S, D> AsMut<LayoutRef<A, D>> for ArrayBase<S, D>
190where S: RawData<Elem = A>
191{
192 fn as_mut(&mut self) -> &mut LayoutRef<A, D>
193 {
194 let parts: &mut ArrayPartsUnsized<S::Elem, D> = &mut self.parts;
195 let ptr = (parts as *mut ArrayPartsUnsized<S::Elem, D>) as *mut LayoutRef<S::Elem, D>;
196 unsafe { &mut *ptr }
197 }
198}
199
200// A4: &ArrayRef -AR-> &RawRef
201impl<A, D> AsRef<RawRef<A, D>> for ArrayRef<A, D>
202{
203 fn as_ref(&self) -> &RawRef<A, D>
204 {
205 self
206 }
207}
208
209// A4: &mut ArrayRef -AM-> &mut RawRef
210impl<A, D> AsMut<RawRef<A, D>> for ArrayRef<A, D>
211{
212 fn as_mut(&mut self) -> &mut RawRef<A, D>
213 {
214 self
215 }
216}
217
218// A4: &ArrayRef -AR-> &LayoutRef
219impl<A, D> AsRef<LayoutRef<A, D>> for ArrayRef<A, D>
220{
221 fn as_ref(&self) -> &LayoutRef<A, D>
222 {
223 self
224 }
225}
226
227// A4: &mut ArrayRef -AM-> &mut LayoutRef
228impl<A, D> AsMut<LayoutRef<A, D>> for ArrayRef<A, D>
229{
230 fn as_mut(&mut self) -> &mut LayoutRef<A, D>
231 {
232 self
233 }
234}
235
236// A5: &RawRef -AR-> &LayoutRef
237impl<A, D> AsRef<LayoutRef<A, D>> for RawRef<A, D>
238{
239 fn as_ref(&self) -> &LayoutRef<A, D>
240 {
241 self
242 }
243}
244
245// A5: &mut RawRef -AM-> &mut LayoutRef
246impl<A, D> AsMut<LayoutRef<A, D>> for RawRef<A, D>
247{
248 fn as_mut(&mut self) -> &mut LayoutRef<A, D>
249 {
250 self
251 }
252}
253
254// A6: &RawRef -AR-> &RawRef
255impl<A, D> AsRef<RawRef<A, D>> for RawRef<A, D>
256{
257 fn as_ref(&self) -> &RawRef<A, D>
258 {
259 self
260 }
261}
262
263// A6: &mut RawRef -AM-> &mut RawRef
264impl<A, D> AsMut<RawRef<A, D>> for RawRef<A, D>
265{
266 fn as_mut(&mut self) -> &mut RawRef<A, D>
267 {
268 self
269 }
270}
271
272// A6: &LayoutRef -AR-> &LayoutRef
273impl<A, D> AsRef<LayoutRef<A, D>> for LayoutRef<A, D>
274{
275 fn as_ref(&self) -> &LayoutRef<A, D>
276 {
277 self
278 }
279}
280
281// A6: &mut LayoutRef -AR-> &mut LayoutRef
282impl<A, D> AsMut<LayoutRef<A, D>> for LayoutRef<A, D>
283{
284 fn as_mut(&mut self) -> &mut LayoutRef<A, D>
285 {
286 self
287 }
288}
289
290/// # Safety
291///
292/// Usually the pointer would be bad to just clone, as we'd have aliasing
293/// and completely separated references to the same data. However, it is
294/// impossible to read the data behind the pointer from a LayoutRef (this
295/// is a safety invariant that *must* be maintained), and therefore we can
296/// Clone and Copy as desired.
297impl<A, D: Clone> Clone for ArrayPartsSized<A, D>
298{
299 fn clone(&self) -> Self
300 {
301 Self {
302 dim: self.dim.clone(),
303 strides: self.strides.clone(),
304 ptr: self.ptr,
305 _dst_control: [0; 0],
306 }
307 }
308}
309
310impl<A, D: Clone + Copy> Copy for ArrayPartsSized<A, D> {}
311
312impl<S, D> Borrow<RawRef<S::Elem, D>> for ArrayBase<S, D>
313where S: RawData
314{
315 fn borrow(&self) -> &RawRef<S::Elem, D>
316 {
317 self.as_ref()
318 }
319}
320
321impl<S, D> BorrowMut<RawRef<S::Elem, D>> for ArrayBase<S, D>
322where S: RawDataMut
323{
324 fn borrow_mut(&mut self) -> &mut RawRef<S::Elem, D>
325 {
326 self.as_mut()
327 }
328}
329
330impl<S, D> Borrow<ArrayRef<S::Elem, D>> for ArrayBase<S, D>
331where S: Data
332{
333 fn borrow(&self) -> &ArrayRef<S::Elem, D>
334 {
335 self
336 }
337}
338
339impl<S, D> BorrowMut<ArrayRef<S::Elem, D>> for ArrayBase<S, D>
340where
341 S: DataMut,
342 D: Dimension,
343{
344 fn borrow_mut(&mut self) -> &mut ArrayRef<S::Elem, D>
345 {
346 self
347 }
348}
349
350impl<A, D> ToOwned for ArrayRef<A, D>
351where
352 A: Clone,
353 D: Dimension,
354{
355 type Owned = Array<A, D>;
356
357 fn to_owned(&self) -> Self::Owned
358 {
359 self.to_owned()
360 }
361
362 fn clone_into(&self, target: &mut Array<A, D>)
363 {
364 target.zip_mut_with(self, |tgt, src| tgt.clone_from(src));
365 }
366}
367
368/// Shortcuts for the various as_ref calls
369impl<A, S, D> ArrayBase<S, D>
370where S: RawData<Elem = A>
371{
372 /// Cheaply convert a reference to the array to an &LayoutRef
373 pub fn as_layout_ref(&self) -> &LayoutRef<A, D>
374 {
375 self.as_ref()
376 }
377
378 /// Cheaply and mutably convert a reference to the array to an &LayoutRef
379 pub fn as_layout_ref_mut(&mut self) -> &mut LayoutRef<A, D>
380 {
381 self.as_mut()
382 }
383
384 /// Cheaply convert a reference to the array to an &RawRef
385 pub fn as_raw_ref(&self) -> &RawRef<A, D>
386 {
387 self.as_ref()
388 }
389
390 /// Cheaply and mutably convert a reference to the array to an &RawRef
391 pub fn as_raw_ref_mut(&mut self) -> &mut RawRef<A, D>
392 where S: RawDataMut<Elem = A>
393 {
394 self.as_mut()
395 }
396}
397
398/// Tests that a mem::swap can't compile by putting it into a doctest
399///
400/// ```compile_fail
401/// let mut x = Array1::from_vec(vec![0, 1, 2]);
402/// {
403/// let mut y = Array1::from_vec(vec![4, 5, 6]);
404/// let x_ref = x.as_layout_ref_mut();
405/// let y_ref = y.as_layout_ref_mut();
406/// core::mem::swap(x_ref, y_ref);
407/// }
408/// ```
409#[allow(dead_code)]
410fn test_no_swap_via_doctests() {}