1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//!
//! This crate provides convenient low-level utility functions for reinterpreting data.
//! This includes `Vec`s and `slice`s. These functions are intrinsically unsafe but are very
//! useful in performance critical code since they avoid additional copies.
//!
//! The goal of this crate is to provide some memory safety along the boundaries of `Vec`s and
//! `slice`s to reduce the boilerplate for reinterpreting data.
//!
//! These functions check that the source and target arrays have the same size, however they don't
//! check for safety of converting the contained types.
//!
//! It is possible to write safe wrappers for converting collections of concrete types using these
//! functions, however this is out of the scope of this crate.
//!
//! # Examples
//!
//! ```rust
//! # extern crate reinterpret;
//! # use reinterpret::*;
//! # fn main() {
//!     let points: Vec<[f64;2]> = vec![
//!         [0.1, 1.0],
//!         [1.2, 1.4],
//!         [0.5, 3.2],
//!     ];
//!     let coordinates: Vec<f64> = vec![0.1, 1.0, 1.2, 1.4, 0.5, 3.2];
//!
//!     let point_coordinates: &[f64] = unsafe { reinterpret_slice(&points) };
//!     assert_eq!(*point_coordinates, *coordinates.as_slice()); // Same data.
//!     assert_eq!(point_coordinates, coordinates.as_slice()); // Same location in memory.
//!
//!     let coordinate_points: &[[f64;2]] = unsafe { reinterpret_slice(&coordinates) };
//!     assert_eq!(*coordinate_points, *points.as_slice()); // Same data.
//!     assert_eq!(coordinate_points, points.as_slice()); // Same location in memory.
//! # }
//! ```
//!
//!
//! # Undefined Behavior
//!
//! There are ways to misuse these functions without causing panics that may produce *undefined
//! behavior*. For instance:
//!
//! ```rust
//! # extern crate reinterpret;
//! # use reinterpret::*;
//! # fn main() {
//!     let a = 1;
//!     let b = 2;
//!     let v = vec![&a, &b];
//!     let mut m: Vec<&mut usize> = unsafe { reinterpret_vec(v) };
//!     *m[0] = 100; // Mutating an immutable variable a!
//!
//!     assert_eq!(a, 100);
//! # }
//! ```
//!
//! It is the users' responsibility to avoid these types of scenarios.

use std::mem::size_of;
use std::slice;

/// Reinterpret a given slice as a slice of another type. This function checks that the resulting
/// slice is appropriately sized.
pub unsafe fn reinterpret_mut_slice<T, S>(slice: &mut [T]) -> &mut [S] {
    let size_t = size_of::<T>();
    let size_s = size_of::<S>();
    let nu_len = if size_t > 0 {
        assert_ne!(
            size_s, 0,
            "Cannot reinterpret a slice of non-zero sized types as a slice of zero sized types."
        );
        // We must be able to split the given slice into appropriately sized chunks.
        assert_eq!(
            (slice.len() * size_t) % size_s,
            0,
            "Slice cannot be safely reinterpreted due to a misaligned size"
        );
        (slice.len() * size_t) / size_s
    } else {
        assert_eq!(
            size_s, 0,
            "Cannot reinterpret a slice of zero sized types as a slice of non-zero sized types."
        );
        slice.len()
    };
    slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut S, nu_len)
}

/// Reinterpret a given slice as a slice of another type. This function checks that the resulting
/// slice is appropriately sized.
pub unsafe fn reinterpret_slice<T, S>(slice: &[T]) -> &[S] {
    let size_t = size_of::<T>();
    let size_s = size_of::<S>();
    let nu_len = if size_t > 0 {
        assert_ne!(
            size_s, 0,
            "Cannot reinterpret a slice of non-zero sized types as a slice of zero sized types."
        );
        // We must be able to split the given slice into appropriately sized chunks.
        assert_eq!(
            (slice.len() * size_t) % size_s,
            0,
            "Slice cannot be safely reinterpreted due to a misaligned size"
        );
        (slice.len() * size_t) / size_s
    } else {
        assert_eq!(
            size_s, 0,
            "Cannot reinterpret a slice of zero sized types as a slice of non-zero sized types."
        );
        slice.len()
    };
    slice::from_raw_parts(slice.as_ptr() as *const S, nu_len)
}

/// Reinterpret a given `Vec` as a `Vec` of another type. This function checks that the resulting
/// `Vec` is appropriately sized.
pub unsafe fn reinterpret_vec<T, S>(mut vec: Vec<T>) -> Vec<S> {
    let size_t = size_of::<T>();
    let size_s = size_of::<S>();
    let nu_vec = if size_t > 0 {
        assert_ne!(
            size_s, 0,
            "Cannot reinterpret a Vec of non-zero sized types as a Vec of zero sized types."
        );
        // We must be able to split the given vec into appropriately sized chunks.
        assert_eq!(
            (vec.len() * size_t) % size_s,
            0,
            "Vec cannot be safely reinterpreted due to a misaligned size"
        );
        let nu_len = (vec.len() * size_t) / size_s;
        assert_eq!(
            (vec.capacity() * size_t) % size_s,
            0,
            "Vec cannot be safely reinterpreted due to a misaligned capacity"
        );
        let nu_capacity = (vec.capacity() * size_t) / size_s;
        let vec_ptr = vec.as_mut_ptr();
        Vec::from_raw_parts(vec_ptr as *mut S, nu_len, nu_capacity)
    } else {
        assert_eq!(
            size_s, 0,
            "Cannot reinterpret a Vec of zero sized types as a Vec of non-zero sized types."
        );
        let nu_len = vec.len();
        let nu_capacity = vec.capacity();
        debug_assert_eq!(
            nu_capacity,
            (-1isize) as usize,
            "Capacity should be -1 for 0 sized types. (bug)"
        );
        let vec_ptr = vec.as_mut_ptr();
        Vec::from_raw_parts(vec_ptr as *mut S, nu_len, nu_capacity)
    };
    ::std::mem::forget(vec);
    nu_vec
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Check that we can reinterpret a slice of `[f64;3]`s as a slice of `f64`s.
    #[test]
    fn reinterpret_slice_test() {
        let vec: Vec<[f64; 3]> = vec![[0.1, 1.0, 2.0], [1.2, 1.4, 2.1], [0.5, 3.2, 4.0]];
        let flat: Vec<f64> = vec![0.1, 1.0, 2.0, 1.2, 1.4, 2.1, 0.5, 3.2, 4.0];
        let nu_flat: &[f64] = unsafe { reinterpret_slice(vec.as_slice()) };
        assert_eq!(*nu_flat, *flat.as_slice()); // Same data.
        assert_eq!(nu_flat, flat.as_slice()); // Same memory.

        let nu_slice: &[[f64; 3]] = unsafe { reinterpret_slice(flat.as_slice()) };
        assert_eq!(*nu_slice, *vec.as_slice()); // Same data.
        assert_eq!(nu_slice, vec.as_slice()); // Same memory.
    }

    #[test]
    fn reinterpret_mut_slice_test() {
        let vec: Vec<[f64; 3]> = vec![[0.5, 1.0, 2.0], [1.2, 1.4, 2.1], [0.5, 3.2, 4.0]];
        let flat_mut = &mut [-0.5, -1.0, -1.0, 0.2, -0.6, -0.9, -0.5, 1.2, 1.0];

        let nu_mut_slice: &mut [[f64; 3]] = unsafe { reinterpret_mut_slice(flat_mut) };
        for v in nu_mut_slice.iter_mut() {
            v[0] += 1.0;
            v[1] += 2.0;
            v[2] += 3.0;
        }

        assert_eq!(nu_mut_slice, vec.as_slice());
    }

    #[test]
    fn reinterpret_vec_test() {
        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]];
        let vec = vec![-0.5, -1.0, -1.0, 0.2, -0.6, -0.9, -0.5, 1.2, 1.0];
        let mut nu_vec: Vec<[f64; 3]> = unsafe { reinterpret_vec(vec.clone()) };
        for v in nu_vec.iter_mut() {
            v[0] += 1.0;
            v[1] += 2.0;
            v[2] += 3.0;
        }

        assert_eq!(nu_vec, exp_vec);
    }

    /// Test reinterpreting collections of zero size structs.
    #[test]
    fn zero_size_test() {
        #[derive(Debug, Clone, PartialEq)]
        struct Foo {
            a: (),
            b: (),
        }

        let exp_vec: Vec<Foo> = vec![Foo { a: (), b: () }, Foo { a: (), b: () }];
        let mut mut_vec = vec![(), ()];
        let vec = mut_vec.clone();
        let mut_slice = mut_vec.as_mut_slice();
        let slice = vec.as_slice();
        let exp_slice = exp_vec.as_slice();

        // Convert to a collection of Foo.
        let nu_vec: Vec<Foo> = unsafe { reinterpret_vec(vec.clone()) };
        assert_eq!(nu_vec, exp_vec);

        let nu_slice: &[Foo] = unsafe { reinterpret_slice(slice) };
        assert_eq!(nu_slice, exp_slice);

        let nu_mut_slice: &mut [Foo] = unsafe { reinterpret_mut_slice(mut_slice) };
        assert_eq!(nu_mut_slice, exp_slice);

        // Convert back to a collection of ().
        let old_vec: Vec<()> = unsafe { reinterpret_vec(nu_vec.clone()) };
        assert_eq!(vec, old_vec);

        let old_slice: &[()] = unsafe { reinterpret_mut_slice(nu_mut_slice) };
        assert_eq!(slice, old_slice);
    }
}