Skip to content

Commit eba364f

Browse files
committed
add slice::{from_ptr_range, from_mut_ptr_range}
1 parent e90c5fb commit eba364f

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

library/core/src/slice/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ pub use raw::{from_raw_parts, from_raw_parts_mut};
6969
#[stable(feature = "from_ref", since = "1.28.0")]
7070
pub use raw::{from_mut, from_ref};
7171

72+
#[unstable(feature = "slice_from_ptr_range", issue = "none")]
73+
pub use raw::{from_mut_ptr_range, from_ptr_range};
74+
7275
// This function is public only because there is no other way to unit test heapsort.
7376
#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
7477
pub use sort::heapsort;

library/core/src/slice/raw.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,111 @@ pub const fn from_ref<T>(s: &T) -> &[T] {
177177
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
178178
array::from_mut(s)
179179
}
180+
181+
/// Forms a slice from a pointer range.
182+
///
183+
/// This function is useful for interacting with foreign interfaces which
184+
/// use two pointers to refer to a range of elements in memory, as is
185+
/// common in C++.
186+
///
187+
/// # Safety
188+
///
189+
/// Behavior is undefined if any of the following conditions are violated:
190+
///
191+
/// * The `start` pointer of the range must be a [valid] and properly aligned pointer
192+
/// to the first element of a slice.
193+
///
194+
/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past*
195+
/// the last element.
196+
///
197+
/// * The range must contain `N` consecutive properly initialized values of type `T`:
198+
///
199+
/// * The entire memory range of this slice must be contained within a single allocated object!
200+
/// Slices can never span across multiple allocated objects.
201+
///
202+
/// * The memory referenced by the returned slice must not be mutated for the duration
203+
/// of lifetime `'a`, except inside an `UnsafeCell`.
204+
///
205+
/// * The total length of the range must be no larger than `isize::MAX`.
206+
/// See the safety documentation of [`pointer::offset`].
207+
///
208+
/// Note that a range created from [`slice::as_ptr_range`] fulfills these requirements.
209+
///
210+
/// # Caveat
211+
///
212+
/// The lifetime for the returned slice is inferred from its usage. To
213+
/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
214+
/// source lifetime is safe in the context, such as by providing a helper
215+
/// function taking the lifetime of a host value for the slice, or by explicit
216+
/// annotation.
217+
///
218+
/// # Examples
219+
///
220+
/// ```
221+
/// #![feature(slice_from_ptr_range)]
222+
///
223+
/// use core::slice;
224+
///
225+
/// let x = [1, 2, 3, 4, 5];
226+
/// let range = x.as_ptr_range();
227+
///
228+
/// unsafe {
229+
/// assert_eq!(slice::from_ptr_range(range), &x);
230+
/// }
231+
/// ```
232+
///
233+
/// [valid]: ptr#safety
234+
#[unstable(feature = "slice_from_ptr_range", issue = "none")]
235+
pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
236+
// SAFETY: the caller must uphold the safety contract for `from_ptr_range`.
237+
unsafe { from_raw_parts(range.start, range.end.offset_from(range.start) as usize) }
238+
}
239+
240+
/// Performs the same functionality as [`from_ptr_range`], except that a
241+
/// mutable slice is returned.
242+
///
243+
/// # Safety
244+
///
245+
/// Behavior is undefined if any of the following conditions are violated:
246+
///
247+
/// * The `start` pointer of the range must be a [valid] and properly aligned pointer
248+
/// to the first element of a slice.
249+
///
250+
/// * The `end` pointer must be a [valid] and properly aligned pointer to *one past*
251+
/// the last element.
252+
///
253+
/// * The range must contain `N` consecutive properly initialized values of type `T`:
254+
///
255+
/// * The entire memory range of this slice must be contained within a single allocated object!
256+
/// Slices can never span across multiple allocated objects.
257+
///
258+
/// * The memory referenced by the returned slice must not be accessed through any other pointer
259+
/// (not derived from the return value) for the duration of lifetime `'a`.
260+
/// Both read and write accesses are forbidden.
261+
///
262+
/// * The total length of the range must be no larger than `isize::MAX`.
263+
/// See the safety documentation of [`pointer::offset`].
264+
///
265+
/// Note that a range created from [`slice::as_mut_ptr_range`] fulfills these requirements.
266+
///
267+
/// # Examples
268+
///
269+
/// ```
270+
/// #![feature(slice_from_ptr_range)]
271+
///
272+
/// use core::slice;
273+
///
274+
/// let mut x = [1, 2, 3, 4, 5];
275+
/// let range = x.as_mut_ptr_range();
276+
///
277+
/// unsafe {
278+
/// assert_eq!(slice::from_mut_ptr_range(range), &x);
279+
/// }
280+
/// ```
281+
///
282+
/// [valid]: ptr#safety
283+
#[unstable(feature = "slice_from_ptr_range", issue = "none")]
284+
pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
285+
// SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`.
286+
unsafe { from_raw_parts_mut(range.start, range.end.offset_from(range.start) as usize) }
287+
}

library/core/tests/slice.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,3 +2232,22 @@ fn slice_split_array_mut_out_of_bounds() {
22322232

22332233
v.split_array_mut::<7>();
22342234
}
2235+
2236+
fn test_slice_from_ptr_range() {
2237+
let arr = [1, 2, 3];
2238+
let range = arr.as_ptr_range();
2239+
unsafe {
2240+
assert_eq!(slice::from_ptr_range(range), &arr);
2241+
}
2242+
2243+
let mut arr = ["foo".to_owned(), "bar".to_owned()];
2244+
let range = arr.as_mut_ptr_range();
2245+
unsafe {
2246+
assert_eq!(slice::from_mut_ptr_range(range), &arr);
2247+
}
2248+
2249+
let range: Range<*const Vec<String>> = [].as_ptr_range();
2250+
unsafe {
2251+
assert_eq!(slice::from_ptr_range(range), &[] as &[Vec<String>]);
2252+
}
2253+
}

0 commit comments

Comments
 (0)