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 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
#![unstable(feature = "ptr_metadata", issue = "81513")]
use crate::fmt;
use crate::hash::{Hash, Hasher};
/// 提供任何指向类型的指针元数据类型。
///
/// # 指针元数据
///
/// Rust 中的裸指针类型和引用类型可以认为是由两部分组成:
/// 包含该值的内存地址和一些元数据的数据指针。
///
/// 对于静态大小的类型 (实现 `Sized` traits) 以及 `extern` 类型,指针被称为 `thin`: 元数据的大小为零,其类型为 `()`。
///
///
/// 指向 [动态大小的类型][dst] 的指针被称为 `wide` 或 `fat`,它们具有非零大小的元数据:
///
/// * 对于最后一个字段是 DST 的结构体,元数据是最后一个字段的元数据
/// * 对于 `str` 类型,元数据是 `usize` 的长度 (以字节为单位)
/// * 对于 `[T]` 之类的切片类型,元数据是 `usize` 中项的长度
/// * 对于 `dyn SomeTrait` 之类的 trait 对象,元数据为 [`DynMetadata<Self>`][DynMetadata] (例如 `DynMetadata<dyn SomeTrait>`)
///
/// 在 future 中,Rust 语言可能会获得具有不同指针元数据的新型类型。
///
/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
///
/// # The `Pointee` trait
///
/// 这个 trait 的重点是它的 `Metadata` 关联类型,像上面讲的一样,它是 `()` 或 `usize` 或 `DynMetadata<_>`。
/// 它会针对每种类型自动实现。
/// 即使没有相应的限制,也可以假定它是在泛型上下文中实现的。
///
/// # Usage
///
/// 可以使用 [`to_raw_parts`] 方法将裸指针分解为数据地址和元数据组件。
///
/// 或者,可以使用 [`metadata`] 函数单独提取元数据。
/// 可以将引用传递给 [`metadata`] 并进行隐式强制。
///
/// 可以使用 [`from_raw_parts`] 或 [`from_raw_parts_mut`] 将 (possibly-wide) 指针从其地址和元数据放回原处。
///
/// [`to_raw_parts`]: *const::to_raw_parts
///
///
///
///
///
///
///
///
///
#[lang = "pointee_trait"]
#[rustc_deny_explicit_impl]
pub trait Pointee {
/// 指针中的元数据类型,并引用 `Self`。
#[lang = "metadata_type"]
// NOTE: 保持 `library/core/src/ptr/metadata.rs` 中 `static_assert_expected_bounds_for_metadata` 中的 trait bounds 与此处的同步:
//
//
type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
}
/// 实现此 trait 别名的类型的指针为 `thin`。
///
/// 这包括静态 `Sized` 类型和 `extern` 类型。
///
/// # Example
///
/// ```rust
/// #![feature(ptr_metadata)]
///
/// fn this_never_panics<T: std::ptr::Thin>() {
/// assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::<usize>())
/// }
/// ```
#[unstable(feature = "ptr_metadata", issue = "81513")]
// NOTE: 在 trait 别名在语言中稳定之前难道不能稳定它吗?
pub trait Thin = Pointee<Metadata = ()>;
/// 提取指针的元数据组件。
///
/// `*mut T`,`&T` 或 `&mut T` 类型的值可以隐式强制转换为 `*const T`,因此可以直接传递给此函数。
///
///
/// # Example
///
/// ```
/// #![feature(ptr_metadata)]
///
/// assert_eq!(std::ptr::metadata("foo"), 3_usize);
/// ```
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
// SAFETY: 因为 *const T 和 PtrComponents<T> 具有相同的内存布局,所以从 `PtrRepr` union 访问值是安全的。
// 只有 std 可以做出此保证。
//
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
}
/// 根据数据地址和元数据形成 (possibly-wide) 裸指针。
///
/// 此函数是安全的,但是返回的指针对于解引用并不一定是安全的。
/// 对于切片,请参见 [`slice::from_raw_parts`] 的文档以了解安全要求。
/// 对于 trait 对象,元数据必须来自指向相同底层 erased 类型的指针。
///
/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn from_raw_parts<T: ?Sized>(
data_address: *const (),
metadata: <T as Pointee>::Metadata,
) -> *const T {
// SAFETY: 因为 *const T 和 PtrComponents<T> 具有相同的内存布局,所以从 `PtrRepr` union 访问值是安全的。
// 只有 std 可以做出此保证。
//
unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
}
/// 执行与 [`from_raw_parts`] 相同的功能,除了返回原始 `*mut` 指针 (与原始 `*const` 指针相反) 之外。
///
///
/// 有关更多详细信息,请参见 [`from_raw_parts`] 的文档。
#[unstable(feature = "ptr_metadata", issue = "81513")]
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn from_raw_parts_mut<T: ?Sized>(
data_address: *mut (),
metadata: <T as Pointee>::Metadata,
) -> *mut T {
// SAFETY: 因为 *const T 和 PtrComponents<T> 具有相同的内存布局,所以从 `PtrRepr` union 访问值是安全的。
// 只有 std 可以做出此保证。
//
unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
}
#[repr(C)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
mut_ptr: *mut T,
components: PtrComponents<T>,
}
#[repr(C)]
struct PtrComponents<T: ?Sized> {
data_address: *const (),
metadata: <T as Pointee>::Metadata,
}
// 需要避免 `T: Copy` 绑定的手动提示。
impl<T: ?Sized> Copy for PtrComponents<T> {}
// 需要避免 `T: Clone` 绑定的手动提示。
impl<T: ?Sized> Clone for PtrComponents<T> {
fn clone(&self) -> Self {
*self
}
}
/// `Dyn = dyn SomeTrait` trait 对象类型的元数据。
///
/// 它是指向 vtable (虚拟调用表) 的指针,该表表示操作存储在 trait 对象内部的具体类型所需的所有信息。
/// 该 vtable 尤其包含:
///
/// * 类型大小
/// * 类型对齐
/// * 指向该类型的 `drop_in_place` impl 的指针 (对于纯旧数据,它可能是 no-op)
/// * 指向 trait 类型实现的所有方法的指针
///
/// 请注意,前三个是特殊的,因为它们是分配,丢弃和释放任何 trait 对象所必需的。
///
/// 可以使用不是 `dyn` trait 对象 (例如 `DynMetadata<u64>`) 的类型参数来命名此结构体,但不能获得该结构体的有意义的值。
///
///
///
///
#[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: ?Sized> {
vtable_ptr: &'static VTable,
phantom: crate::marker::PhantomData<Dyn>,
}
extern "C" {
/// 用于访问 vtables 的不透明类型。
///
/// `DynMetadata::size_of` 等的私有实现详细信息
/// 在这个指针后面实际上没有任何抽象机内存。
type VTable;
}
impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// 返回与此 vtable 关联的类型的大小。
#[inline]
pub fn size_of(self) -> usize {
// 请注意,"存储在虚表中的大小" *不* 与 "size_of_val_raw 的结果" 相同。
// 考虑像 `&(i32, dyn Send)` 这样的引用: vtable 将只存储 `Send` 部分的大小!
//
// SAFETY: DynMetadata 总是包含一个有效的 vtable 指针
return unsafe {
crate::intrinsics::vtable_size(self.vtable_ptr as *const VTable as *const ())
};
}
/// 返回与此 vtable 关联的类型的对齐方式。
#[inline]
pub fn align_of(self) -> usize {
// SAFETY: DynMetadata 总是包含一个有效的 vtable 指针
return unsafe {
crate::intrinsics::vtable_align(self.vtable_ptr as *const VTable as *const ())
};
}
/// 将大小和对齐方式一起返回为 `Layout`
#[inline]
pub fn layout(self) -> crate::alloc::Layout {
// SAFETY: 编译器针对特定的 Rust 类型发出此 vtable,已知该类型具有有效的布局。
// 与 `Layout::for_value` 中的原理相同。
unsafe { crate::alloc::Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
}
}
unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
}
}
// 避免 `Dyn: $Trait` 边界所需的手动提示。
impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
#[inline]
fn eq(&self, other: &Self) -> bool {
crate::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
}
}
impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
#[inline]
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
(self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
}
}
impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
crate::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
}
}