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
//! 创建 `&[T]` 和 `&mut [T]` 的 free 函数。
use crate::array;
use crate::ptr;
/// 根据指针和长度形成切片。
///
/// `len` 参数是 **元素** 的数量,而不是字节数。
///
/// # Safety
///
/// 如果违反以下任一条件,则行为是未定义的:
///
/// * 对于 `len * mem::size_of::<T>()` 多个字节的读取,`data` 必须是 [valid],并且必须正确对齐。这尤其意味着:
///
/// * 该切片的整个存储范围必须包含在一个分配的对象中!
/// 切片永远不能跨越多个分配的对象。请参见 [下文](#incorrect-usage) 了解一个没有考虑到这一点的错误示例。
/// * 即使对于零长度切片,`data` 也必须非空且对齐。
/// 这样做的一个原因是,枚举布局优化可能依赖于对齐的引用 (包括任何长度的切片) 和非空值,以将它们与其他数据区分开。
/// 您可以使用 [`NonNull::dangling()`] 获得可用作零长度切片的 `data` 的指针。
///
/// * `data` 必须指向 `len` 类型的 `T` 类型的连续正确初始化值。
///
/// * 返回的切片引用的内存在生命周期 `'a` 期间不得更改,除非在 `UnsafeCell` 内部。
///
/// * 切片的总大小 `len * mem::size_of::<T>()` 必须不大于 `isize::MAX`。
/// 请参见 [`pointer::offset`] 的安全文档。
///
/// # Caveat
///
/// 从使用中可以推断出返回切片的生命周期。
/// 为防止意外滥用,建议将生命周期与生命周期中任何安全的来源联系起来,例如通过提供一个辅助函数,获取切片的宿主值的生命周期,或通过明确的注解法。
///
///
/// # Examples
///
/// ```
/// use std::slice;
///
/// // 显示单个元素的切片
/// let x = 42;
/// let ptr = &x as *const _;
/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
/// assert_eq!(slice[0], 42);
/// ```
///
/// ### 用法不正确
///
/// 下面的 `join_slices` 函数是不健全的 ⚠️
///
/// ```rust,no_run
/// use std::slice;
///
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
/// let fst_end = fst.as_ptr().wrapping_add(fst.len());
/// let snd_start = snd.as_ptr();
/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
/// unsafe {
/// // 上面的断言确保 `fst` 和 `snd` 是连续的,但是它们仍可能包含在 _different allocated objects_ 中,在这种情况下,创建此切片是未定义的行为。
/////
/////
/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
/// }
/// }
///
/// fn main() {
/// // `a` 和 `b` 是不同的分配对象...
/// let a = 42;
/// let b = 27;
/// // ... 但这可能会连续地放在内存中:一个 | b |
/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
/// }
/// ```
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
///
///
///
///
///
///
///
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_check_data_len(data, len);
// SAFETY: 调用者必须遵守 `from_raw_parts` 的安全保证。
unsafe { &*ptr::slice_from_raw_parts(data, len) }
}
/// 执行与 [`from_raw_parts`] 相同的功能,除了返回可变切片。
///
/// # Safety
///
/// 如果违反以下任一条件,则行为是未定义的:
///
/// * 对于 `len * mem::size_of::<T>()` 多个字节的读取和写入,`data` 必须是 [valid],并且必须正确对齐。这尤其意味着:
///
/// * 该切片的整个存储范围必须包含在一个分配的对象中!
/// 切片永远不能跨越多个分配的对象。
/// * 即使对于零长度切片,`data` 也必须非空且对齐。
/// 这样做的一个原因是,枚举布局优化可能依赖于对齐的引用 (包括任何长度的切片) 和非空值,以将它们与其他数据区分开。
///
/// 您可以使用 [`NonNull::dangling()`] 获得可用作零长度切片的 `data` 的指针。
///
/// * `data` 必须指向 `len` 类型的 `T` 类型的连续正确初始化值。
///
/// * 在生命周期 `'a` 的持续时间内,不得通过任何其他指针 (不是从返回值派生) 访问返回的切片引用的内存。
/// 读取和写入访问均被禁止。
///
/// * 切片的总大小 `len * mem::size_of::<T>()` 必须不大于 `isize::MAX`。
/// 请参见 [`pointer::offset`] 的安全文档。
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
///
///
///
///
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
debug_check_data_len(data as _, len);
// SAFETY: 调用者必须遵守 `from_raw_parts_mut` 的安全保证。
unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}
// 在调试版本中,检查 `data` 指针是否对齐且不为 null,并且具有给定 `len` 的切片将覆盖不到一半的地址空间
#[cfg(debug_assertions)]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
fn rt_check<T>(data: *const T) {
use crate::intrinsics::is_aligned_and_not_null;
assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
}
const fn noop<T>(_: *const T) {}
// SAFETY:
//
// `rt_check` 只是一个调试断言,提示用户他们正在导致 UB,它不是安全必需的 (安全性必须由 `from_raw_parts[_mut]` 调用者保证)。
//
//
// 根据我们的安全先决条件,我们可以假设上面的断言永远不会失败。
// 因此,noop 和 rt_check 显然是等价的。
//
unsafe {
crate::intrinsics::const_eval_select((data,), noop, rt_check);
}
assert!(
crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering at least half the address space"
);
}
#[cfg(not(debug_assertions))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
/// 将引用转换为 T 转换为长度为 1 的切片 (不进行复制)。
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_ref<T>(s: &T) -> &[T] {
array::from_ref(s)
}
/// 将引用转换为 T 转换为长度为 1 的切片 (不进行复制)。
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
array::from_mut(s)
}