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)
}