reinterpret/
lib.rs

1//!
2//! This crate provides convenient low-level utility functions for reinterpreting data.
3//! This includes `Vec`s and `slice`s. These functions are intrinsically unsafe but are very
4//! useful in performance critical code since they avoid additional copies.
5//!
6//! The goal of this crate is to provide some memory safety along the boundaries of `Vec`s and
7//! `slice`s to reduce the boilerplate for reinterpreting data.
8//!
9//! These functions check that the source and target arrays have the same size, however they don't
10//! check for safety of converting the contained types.
11//!
12//! It is possible to write safe wrappers for converting collections of concrete types using these
13//! functions, however this is out of the scope of this crate.
14//!
15//! # Examples
16//!
17//! ```rust
18//! # extern crate reinterpret;
19//! # use reinterpret::*;
20//! # fn main() {
21//!     let points: Vec<[f64;2]> = vec![
22//!         [0.1, 1.0],
23//!         [1.2, 1.4],
24//!         [0.5, 3.2],
25//!     ];
26//!     let coordinates: Vec<f64> = vec![0.1, 1.0, 1.2, 1.4, 0.5, 3.2];
27//!
28//!     let point_coordinates: &[f64] = unsafe { reinterpret_slice(&points) };
29//!     assert_eq!(*point_coordinates, *coordinates.as_slice()); // Same data.
30//!     assert_eq!(point_coordinates, coordinates.as_slice()); // Same location in memory.
31//!
32//!     let coordinate_points: &[[f64;2]] = unsafe { reinterpret_slice(&coordinates) };
33//!     assert_eq!(*coordinate_points, *points.as_slice()); // Same data.
34//!     assert_eq!(coordinate_points, points.as_slice()); // Same location in memory.
35//! # }
36//! ```
37//!
38//!
39//! # Undefined Behavior
40//!
41//! There are ways to misuse these functions without causing panics that may produce *undefined
42//! behavior*. For instance:
43//!
44//! ```rust
45//! # extern crate reinterpret;
46//! # use reinterpret::*;
47//! # fn main() {
48//!     let a = 1;
49//!     let b = 2;
50//!     let v = vec![&a, &b];
51//!     let mut m: Vec<&mut usize> = unsafe { reinterpret_vec(v) };
52//!     *m[0] = 100; // Mutating an immutable variable a!
53//!
54//!     assert_eq!(a, 100);
55//! # }
56//! ```
57//!
58//! It is the users' responsibility to avoid these types of scenarios.
59
60use std::mem::size_of;
61use std::slice;
62
63/// Reinterpret a given slice as a slice of another type. This function checks that the resulting
64/// slice is appropriately sized.
65pub unsafe fn reinterpret_mut_slice<T, S>(slice: &mut [T]) -> &mut [S] {
66    let size_t = size_of::<T>();
67    let size_s = size_of::<S>();
68    let nu_len = if size_t > 0 {
69        assert_ne!(
70            size_s, 0,
71            "Cannot reinterpret a slice of non-zero sized types as a slice of zero sized types."
72        );
73        // We must be able to split the given slice into appropriately sized chunks.
74        assert_eq!(
75            (slice.len() * size_t) % size_s,
76            0,
77            "Slice cannot be safely reinterpreted due to a misaligned size"
78        );
79        (slice.len() * size_t) / size_s
80    } else {
81        assert_eq!(
82            size_s, 0,
83            "Cannot reinterpret a slice of zero sized types as a slice of non-zero sized types."
84        );
85        slice.len()
86    };
87    slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut S, nu_len)
88}
89
90/// Reinterpret a given slice as a slice of another type. This function checks that the resulting
91/// slice is appropriately sized.
92pub unsafe fn reinterpret_slice<T, S>(slice: &[T]) -> &[S] {
93    let size_t = size_of::<T>();
94    let size_s = size_of::<S>();
95    let nu_len = if size_t > 0 {
96        assert_ne!(
97            size_s, 0,
98            "Cannot reinterpret a slice of non-zero sized types as a slice of zero sized types."
99        );
100        // We must be able to split the given slice into appropriately sized chunks.
101        assert_eq!(
102            (slice.len() * size_t) % size_s,
103            0,
104            "Slice cannot be safely reinterpreted due to a misaligned size"
105        );
106        (slice.len() * size_t) / size_s
107    } else {
108        assert_eq!(
109            size_s, 0,
110            "Cannot reinterpret a slice of zero sized types as a slice of non-zero sized types."
111        );
112        slice.len()
113    };
114    slice::from_raw_parts(slice.as_ptr() as *const S, nu_len)
115}
116
117/// Reinterpret a given `Vec` as a `Vec` of another type. This function checks that the resulting
118/// `Vec` is appropriately sized.
119pub unsafe fn reinterpret_vec<T, S>(mut vec: Vec<T>) -> Vec<S> {
120    let size_t = size_of::<T>();
121    let size_s = size_of::<S>();
122    let nu_vec = if size_t > 0 {
123        assert_ne!(
124            size_s, 0,
125            "Cannot reinterpret a Vec of non-zero sized types as a Vec of zero sized types."
126        );
127        // We must be able to split the given vec into appropriately sized chunks.
128        assert_eq!(
129            (vec.len() * size_t) % size_s,
130            0,
131            "Vec cannot be safely reinterpreted due to a misaligned size"
132        );
133        let nu_len = (vec.len() * size_t) / size_s;
134        assert_eq!(
135            (vec.capacity() * size_t) % size_s,
136            0,
137            "Vec cannot be safely reinterpreted due to a misaligned capacity"
138        );
139        let nu_capacity = (vec.capacity() * size_t) / size_s;
140        let vec_ptr = vec.as_mut_ptr();
141        Vec::from_raw_parts(vec_ptr as *mut S, nu_len, nu_capacity)
142    } else {
143        assert_eq!(
144            size_s, 0,
145            "Cannot reinterpret a Vec of zero sized types as a Vec of non-zero sized types."
146        );
147        let nu_len = vec.len();
148        let nu_capacity = vec.capacity();
149        debug_assert_eq!(
150            nu_capacity,
151            (-1isize) as usize,
152            "Capacity should be -1 for 0 sized types. (bug)"
153        );
154        let vec_ptr = vec.as_mut_ptr();
155        Vec::from_raw_parts(vec_ptr as *mut S, nu_len, nu_capacity)
156    };
157    ::std::mem::forget(vec);
158    nu_vec
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164
165    /// Check that we can reinterpret a slice of `[f64;3]`s as a slice of `f64`s.
166    #[test]
167    fn reinterpret_slice_test() {
168        let vec: Vec<[f64; 3]> = vec![[0.1, 1.0, 2.0], [1.2, 1.4, 2.1], [0.5, 3.2, 4.0]];
169        let flat: Vec<f64> = vec![0.1, 1.0, 2.0, 1.2, 1.4, 2.1, 0.5, 3.2, 4.0];
170        let nu_flat: &[f64] = unsafe { reinterpret_slice(vec.as_slice()) };
171        assert_eq!(*nu_flat, *flat.as_slice()); // Same data.
172        assert_eq!(nu_flat, flat.as_slice()); // Same memory.
173
174        let nu_slice: &[[f64; 3]] = unsafe { reinterpret_slice(flat.as_slice()) };
175        assert_eq!(*nu_slice, *vec.as_slice()); // Same data.
176        assert_eq!(nu_slice, vec.as_slice()); // Same memory.
177    }
178
179    #[test]
180    fn reinterpret_mut_slice_test() {
181        let vec: Vec<[f64; 3]> = vec![[0.5, 1.0, 2.0], [1.2, 1.4, 2.1], [0.5, 3.2, 4.0]];
182        let flat_mut = &mut [-0.5, -1.0, -1.0, 0.2, -0.6, -0.9, -0.5, 1.2, 1.0];
183
184        let nu_mut_slice: &mut [[f64; 3]] = unsafe { reinterpret_mut_slice(flat_mut) };
185        for v in nu_mut_slice.iter_mut() {
186            v[0] += 1.0;
187            v[1] += 2.0;
188            v[2] += 3.0;
189        }
190
191        assert_eq!(nu_mut_slice, vec.as_slice());
192    }
193
194    #[test]
195    fn reinterpret_vec_test() {
196        let exp_vec: Vec<[f64; 3]> = vec![[0.5, 1.0, 2.0], [1.2, 1.4, 2.1], [0.5, 3.2, 4.0]];
197        let vec = vec![-0.5, -1.0, -1.0, 0.2, -0.6, -0.9, -0.5, 1.2, 1.0];
198        let mut nu_vec: Vec<[f64; 3]> = unsafe { reinterpret_vec(vec.clone()) };
199        for v in nu_vec.iter_mut() {
200            v[0] += 1.0;
201            v[1] += 2.0;
202            v[2] += 3.0;
203        }
204
205        assert_eq!(nu_vec, exp_vec);
206    }
207
208    /// Test reinterpreting collections of zero size structs.
209    #[test]
210    fn zero_size_test() {
211        #[derive(Debug, Clone, PartialEq)]
212        struct Foo {
213            a: (),
214            b: (),
215        }
216
217        let exp_vec: Vec<Foo> = vec![Foo { a: (), b: () }, Foo { a: (), b: () }];
218        let mut mut_vec = vec![(), ()];
219        let vec = mut_vec.clone();
220        let mut_slice = mut_vec.as_mut_slice();
221        let slice = vec.as_slice();
222        let exp_slice = exp_vec.as_slice();
223
224        // Convert to a collection of Foo.
225        let nu_vec: Vec<Foo> = unsafe { reinterpret_vec(vec.clone()) };
226        assert_eq!(nu_vec, exp_vec);
227
228        let nu_slice: &[Foo] = unsafe { reinterpret_slice(slice) };
229        assert_eq!(nu_slice, exp_slice);
230
231        let nu_mut_slice: &mut [Foo] = unsafe { reinterpret_mut_slice(mut_slice) };
232        assert_eq!(nu_mut_slice, exp_slice);
233
234        // Convert back to a collection of ().
235        let old_vec: Vec<()> = unsafe { reinterpret_vec(nu_vec.clone()) };
236        assert_eq!(vec, old_vec);
237
238        let old_slice: &[()] = unsafe { reinterpret_mut_slice(nu_mut_slice) };
239        assert_eq!(slice, old_slice);
240    }
241}