v0 符号格式
v0 符号修饰格式在 RFC 2603 中引入。它具有以下属性
- 它为所有可能最终出现在二进制文件的符号表中的内容提供了明确的字符串编码。
- 它以可逆的方式编码有关泛型参数的信息。
- 修饰后的符号是可解码的,使得反修饰后的形式应易于识别为例如多态函数的某个具体实例。
- 它具有一致的定义,不依赖于对某些语言结构的漂亮打印。
- 符号可以被限制为仅由字符
A-Z
、a-z
、0-9
和_
组成。这有助于确保它是平台无关的,因为其他字符在某些上下文中可能具有特殊含义(例如,MSVCDEF
文件中的.
)。可选支持 Unicode 符号。 - 它力求保持高效,避免不必要的长名称,并避免计算成本高的反修饰操作。
v0 格式不打算与其他修饰方案(如 C++)兼容。
v0 格式不作为 Rust 的稳定 ABI 呈现。此格式目前旨在足够明确,以使反修饰器可以生成符号的合理人类可读形式。存在几个实现定义的 部分,导致无法完全预测给定 Rust 实体将如何编码。
以下部分定义了 v0 符号的编码。符号没有标准化的反修饰形式,尽管提供了有关如何反修饰符号的建议。实现者可以选择以不同的方式进行反修饰。
扩展
将来可能会扩展此格式以添加新标签,因为 Rust 会扩展为新的语言项。为了实现向前兼容性,反修饰器应优雅地处理符号,这些符号的编码中遇到了本文档中未描述的标签字符。例如,他们可以回退到显示修饰后的符号。该格式可以扩展到存在标签字符的任何位置,例如类型规则。现有标签和编码的含义不会更改。
语法表示法
编码符号的格式以扩展的类 BNF 语法中的上下文无关文法表示。可以在符号语法总结中找到统一的摘要。
名称 | 语法 | 示例 | 描述 |
---|---|---|---|
规则 | → | 一个产生式。 | |
串联 | 空格 | 按从左到右的顺序排列的单个元素。 | |
备选方案 | | | 匹配其中一个或另一个。 | |
分组 | () | 将多个元素分组为一个。 | |
重复 | {} | 重复封闭的零次或多次。 | |
选项 | 可选 | 一个可选元素。 | |
字面量 | 等宽字体 | G | 区分大小写的匹配确切字符的终端。 |
符号名称
修饰的符号以两个字符 _R
开头,这是一个前缀,用于将符号标识为 Rust 符号。该前缀可以选择后跟一个十进制数,该数字指定编码版本。此数字当前未使用,并且在当前编码中永远不会出现。紧随其后的是一个 路径,它对实体的路径进行编码。路径后跟一个可选的 实例化箱,它有助于消除可能在单独的箱中多次实例化的实体的歧义。最后一部分是可选的 特定于供应商的后缀。
推荐的反修饰
示例
std::path::PathBuf::new();
箱
mycrate
中PathBuf::new
的符号是_RNvMsr_NtCs3ssYzQotkvD_3std4pathNtB5_7PathBuf3newCs15kBYyAo9fc_7mycrate ├┘└───────────────────────┬──────────────────────┘└──────────┬─────────┘ │ │ │ │ │ └── instantiating-crate path "mycrate" │ └───────────────────────────────────── path to std::path::PathBuf::new └─────────────────────────────────────────────────────────────── `_R` symbol prefix
推荐的反修饰:
<std::path::PathBuf>::new
符号路径
一个 path 表示某个实体的 Rust 路径 的变体。除了使用标识符的典型 Rust 路径段之外,它还使用额外的元素来表示不可命名实体(如 impl
)或单态化项的泛型参数。
初始标签字符可用于确定它表示哪种路径
路径:箱根
crate-root →
C
标识符
一个 crate-root 指示引用箱的模块树根的路径。它由字符 C
后跟箱名称作为 标识符 组成。
箱名称是从定义箱中看到的名称。由于 Rust 支持链接多个名称相同的箱,因此使用歧义消除器来使名称在整个箱图中是唯一的。
推荐的反修饰
一个 crate-root 可以显示为标识符,例如
mycrate
。通常不需要显示标识符中的歧义消除器,但是作为替代形式,歧义消除器可以用十六进制显示,例如
mycrate[ca63f166dbe9294]
。
示例
fn example() {}
箱
mycrate
中example
的符号是_RNvCs15kBYyAo9fc_7mycrate7example │└────┬─────┘││└──┬──┘ │ │ ││ │ │ │ ││ └── crate-root identifier "mycrate" │ │ │└────── length 7 of "mycrate" │ │ └─────── end of base-62-number │ └────────────── disambiguator for crate-root "mycrate" 0xca63f166dbe9293 + 1 └──────────────────── crate-root
推荐的反修饰:
mycrate::example
注意:编译器可能会重用 crate-root 形式来表示任意未作用域、未消除歧义的标识符,例如用于尚未添加到语法中的新基本类型。为此,它将发出一个没有显式歧义消除器的 crate-root,依赖于这种未消除歧义的箱名称实际上不会发生的事实。例如,基本类型
f128
将编码为C4f128
。为了达到预期的效果,反修饰器应永远不渲染箱根的零歧义消除器。也就是说,C4f128
应该显示为f128
而不是f128[0]
。
路径:固有实现
一个 inherent-impl 指示指向固有实现的路径。它由字符 M
后跟一个 实现路径 组成,该路径唯一标识定义该项的 impl 块。紧随其后的是一个 类型,表示 impl 的 Self
类型。
推荐的反修饰
示例
struct Example; impl Example { fn foo() {} }
Example
的 impl 中的foo
的符号是_RNvMs_Cs4Cv8Wi1oAIB_7mycrateNtB4_7Example3foo │├┘└─────────┬──────────┘└────┬──────┘ ││ │ │ ││ │ └── Self type "Example" ││ └─────────────────── path to the impl's parent "mycrate" │└─────────────────────────────── disambiguator 1 └──────────────────────────────── inherent-impl
推荐的反修饰:
<mycrate::Example>::foo
路径:特征实现
一个 trait-impl 指示指向特征实现的路径。它由字符 X
后跟一个指向 impl 父级的 实现路径,后跟一个表示 impl 的 Self
类型的 类型,后跟一个指向该特征的 路径 组成。
推荐的反修饰
一个 trait-impl 可以使用
<
typeas
path>
语法显示为限定路径段。通常不需要显示 实现路径。
示例
struct Example; trait Trait { fn foo(); } impl Trait for Example { fn foo() {} }
Example
的特征 impl 中的foo
的符号是_RNvXCs15kBYyAo9fc_7mycrateNtB2_7ExampleNtB2_5Trait3foo │└─────────┬──────────┘└─────┬─────┘└────┬────┘ │ │ │ │ │ │ │ └── path to the trait "Trait" │ │ └────────────── Self type "Example" │ └──────────────────────────────── path to the impl's parent "mycrate" └─────────────────────────────────────────── trait-impl
推荐的反修饰:
<mycrate::Example as mycrate::Trait>::foo
路径:Impl
一个 impl-path 是用于 固有实现 和 特征实现 的路径,用于指示指向实现父级的路径。它由一个可选的 歧义消除器 后跟一个 路径 组成。路径是指向包含 impl 的父级的路径。歧义消除器可用于区分同一父级内的多个 impl。
推荐的反修饰
通常不需要显示 impl-path(除非需要 impl 的位置)。
示例
struct Example; impl Example { fn foo() {} } impl Example { fn bar() {} }
Example
的 impl 中的foo
的符号是_RNvMCs7qp2U7fqm6G_7mycrateNtB2_7Example3foo └─────────┬──────────┘ │ └── path to the impl's parent crate-root "mycrate"
bar
的符号类似,但它有一个歧义消除器来表示它在不同的 impl 块中。_RNvMs_Cs7qp2U7fqm6G_7mycrateNtB4_7Example3bar ├┘└─────────┬──────────┘ │ │ │ └── path to the impl's parent crate-root "mycrate" └────────────── disambiguator 1
推荐的反修饰
foo
:<mycrate::Example>::foo
bar
:<mycrate::Example>::bar
路径:特征定义
一个 trait-definition 是指向特征定义的路径。它由字符 Y
后跟 类型 组成,该类型是引用者的 Self
类型,后跟指向特征定义的 路径。
推荐的反修饰
一个 trait-definition 可以使用
<
typeas
path>
语法显示为限定路径段。
示例
trait Trait { fn example() {} } struct Example; impl Trait for Example {}
为
Example
实现的特征Trait
中的example
的符号是_RNvYNtCs15kBYyAo9fc_7mycrate7ExampleNtB4_5Trait7exampleB4_ │└──────────────┬───────────────┘└────┬────┘ │ │ │ │ │ └── path to the trait "Trait" │ └──────────────────────── path to the implementing type "mycrate::Example" └──────────────────────────────────────── trait-definition
推荐的反修饰:
<mycrate::Example as mycrate::Trait>::example
路径:嵌套路径
一个 nested-path 是表示可选命名实体的路径。它由字符 N
后跟一个 命名空间(指示实体的命名空间)、后跟一个 路径(该路径是表示实体父级的路径),后跟实体的 标识符 组成。
当实体未命名时,实体的标识符的长度可能为 0。例如,诸如闭包、类似元组的结构构造函数和匿名常量之类的实体可能没有名称。除非歧义消除器为 0,否则标识符可能仍然具有歧义消除器。
推荐的反修饰
可以通过首先显示 路径,然后是
::
分隔符,然后是 标识符 来显示 nested-path。如果 标识符 为空,则不应显示分隔::
。如果指定了 命名空间,则可以添加额外的上下文,例如
路径::{
命名空间 (:
标识符)可选#
歧义消除器作为以 10 为底的数字}
在这里,命名空间
C
可以打印为closure
,而S
可以打印为shim
。其他命名空间可以按照其字符标签打印。如果:
name 部分的名称为空,则可以跳过。如果指定了命名空间,则可以显示标识符中的消歧符。在其他情况下,通常不需要显示消歧符。如果显示,建议将其放在括号中,例如
[284a76a8b41a7fd3]
。如果不存在消歧符,则其值为 0,并且始终可以从显示中省略。
示例
fn main() { let x = || {}; let y = || {}; x(); y(); }
crate
mycrate
中闭包x
的符号是_RNCNvCsgStHSCytQ6I_7mycrate4main0B3_ ││└─────────────┬─────────────┘│ ││ │ │ ││ │ └── identifier with length 0 ││ └───────────────── path to "mycrate::main" │└──────────────────────────────── closure namespace └───────────────────────────────── nested-path
闭包
y
的符号类似,带有一个消歧符_RNCNvCsgStHSCytQ6I_7mycrate4mains_0B3_ ││ │└── base-62-number 0 └─── disambiguator 1 (base-62-number+1)
推荐的反修饰
x
:mycrate::main::{closure#0}
y
:mycrate::main::{closure#1}
路径:泛型参数
一个 generic-args 是表示泛型参数列表的路径。它由字符 I
开头,后跟定义实体的路径,然后是零个或多个 泛型参数,以字符 E
结尾。
每个 泛型参数 可以是一个 生命周期 (以字符 L
开头),一个类型,或者是字符 K
后跟一个表示常量参数的 常量。
推荐的反修饰
一个 generic-args 可以打印为:路径
::
opt<
逗号分隔的参数列表>
。对于类型路径,可以省略::
分隔符(类似于 Rust 的规则)。
示例
fn main() { example([123]); } fn example<T, const N: usize>(x: [T; N]) {}
函数
example
的符号是_RINvCsgStHSCytQ6I_7mycrate7examplelKj1_EB2_ │└──────────────┬───────────────┘││││││ │ │ │││││└── end of generic-args │ │ ││││└─── end of const-data │ │ │││└──── const value `1` │ │ ││└───── const type `usize` │ │ │└────── const generic │ │ └─────── generic type i32 │ └──────────────────────── path to "mycrate::example" └──────────────────────────────────────── generic-args
建议的反向解析:
mycrate::example::<i32, 1>
命名空间
命名空间用于将名称分隔到单独的逻辑组中,从而允许相同的名称避免冲突。它由一个大写或小写 ASCII 字母组成。小写字母保留用于实现内部的消歧类别(反向解析器不应显示它们)。大写字母用于特殊命名空间,反向解析器可以特殊方式显示它们。
大写命名空间是
C
— 一个闭包。S
— 一个 shim。在某些需要中间体的场景中,编译器会添加 shim。例如,具有#[track_caller]
属性的函数的fn()
指针需要一个 shim 来处理隐式的调用者位置。
推荐的反修饰
有关建议的反向解析,请参见嵌套路径。
标识符
undisambiguated-identifier →
u
opt 十进制数_
opt 字节bytes → {UTF-8 字节}
标识符是 路径 中用于引用实体的命名标签。它由一个可选的消歧符和一个未消歧的标识符组成。
消歧符用于消除不应被视为相同的相同标识符的歧义。例如,闭包没有名称,因此消歧符是同一父路径中两个不同闭包之间唯一的区分元素。
未消歧的标识符以可选的 u
字符开头,表示该标识符使用 Punycode 编码。下一部分是 十进制数,表示字节的长度。
在标识符大小之后是一个可选的 _
字符,用于将长度值与标识符本身分开。如果字节以十进制数字或 _
开头,则 _
是必需的,以保持 十进制数 结束和 字节 开始的明确性。
字节是标识符本身,使用 UTF-8 编码。
推荐的反修饰
标识符的显示取决于其上下文。如果它是 Punycode 编码的,则可能在显示之前先进行解码。
消歧符可能会显示,也可能不会显示;请参阅使用标识符的规则的建议。
Punycode 标识符
由于某些环境仅限于 ASCII 字母数字和 _
,Rust 的 Unicode 标识符 可以使用修改版本的 Punycode 进行编码。
例如,函数
mod gödel {
mod escher {
fn bach() {}
}
}
将被 mangled 为
_RNvNtNtCsgOH4LzxkuMq_7mycrateu8gdel_5qa6escher4bach
││└───┬──┘
││ │
││ └── gdel_5qa translates to gödel
│└─────── 8 is the length
└──────── `u` indicates it is a Unicode identifier
标准 Punycode 生成 ([[:ascii:]]+-)?[[:alnum:]]+
形式的字符串。这是有问题的,因为 -
字符(用于将 ASCII 部分与 base-36 编码分开)不在符号的受支持字符集中。因此,Punycode 编码中的 -
字符将替换为 _
。
以下是一些示例
原始 | Punycode | Punycode + 编码 |
---|---|---|
føø | f-5gaa | f_5gaa |
α_ω | _-ylb7e | __ylb7e |
铁锈 | n84amf | n84amf |
🤦 | fq9h | fq9h |
ρυστ | 2xaedc | 2xaedc |
注意:是否使用 Punycode 编码标识符取决于编译器。某些平台可能原生支持 UTF-8 符号,编译器可能会决定直接使用 UTF-8 编码。反向解析器应准备好支持这两种形式。
消歧符
disambiguator →
s
base-62 数
消歧符用于符号 路径 的各个部分,以唯一标识路径元素,这些元素本来是相同的,但不应被视为相同。它以字符 s
开头,后跟一个 base-62 数。
如果未指定消歧符,则可以假定其值为零。否则,在反向解析时,应将值 1 添加到 base-62 数(因此,编码为 _
的 0 的 base-62 数的值为 1)。这允许顺序编码的消歧符使用最少的字节。
推荐的反修饰
消歧符可能会显示,也可能不会显示;请参阅使用消歧符的规则的建议。通常,建议永远不要显示零消歧符,除非它们附带的标识符为空(例如闭包等未命名项)。呈现消歧符时,可以将其缩短到适合上下文的长度,类似于 git 提交哈希很少完整显示的方式。
生命周期
lifetime →
L
base-62 数
生命周期用于编码匿名(编号)生命周期,可以是擦除的或 高阶 的。它以字符 L
开头,后跟一个 base-62 数。索引 0 始终被擦除。从 1 开始的索引(作为 De Bruijn 索引)指向由封闭的 绑定符 绑定的高阶生命周期。
推荐的反修饰
生命周期可以像 Rust 生命周期一样使用单引号显示。
索引 0 应显示为
'_
。对于 引用类型、可变引用类型 或 动态 trait 类型 中的生命周期,不应显示索引 0。可以通过将 De Bruijn 索引转换为 De Bruijn 级别(级别 = 绑定生命周期的数量 - 索引)并为每个级别选择一个唯一名称来显示生命周期。例如,从单个小写字母开始,例如级别 0 的
'a
。级别超过 25 时,可以考虑将数字生命周期打印为'_123
。有关生命周期索引和排序的更多信息,请参见 绑定符。
示例
fn main() { example::<fn(&u8, &u16)>(); } pub fn example<T>() {}
函数
example
的符号是_RINvCs7qp2U7fqm6G_7mycrate7exampleFG0_RL1_hRL0_tEuEB2_ │└┬┘│└┬┘││└┬┘││ │ │ │ │ ││ │ │└── end of input types │ │ │ │ ││ │ └─── type u16 │ │ │ │ ││ └───── lifetime #1 'b │ │ │ │ │└─────── reference type │ │ │ │ └──────── type u8 │ │ │ └────────── lifetime #2 'a │ │ └──────────── reference type │ └────────────── binder with 2 lifetimes └──────────────── function type
建议的反向解析:
mycrate::example::<for<'a, 'b> fn(&'a u8, &'b u16)>
常量
const-data →
n
opt {十六进制数字}_
常量用于编码泛型和类型中使用的常量值。它具有以下形式
常量数据的编码取决于类型
bool
— 值false
编码为0_
,值 true 编码为1_
。char
— 字符的 Unicode 标量值以十六进制编码。- 无符号整数 — 该值以十六进制编码。
- 有符号整数 — 字符
n
是一个前缀,表示它是负数,后跟以十六进制编码的绝对值。
推荐的反修饰
常量可以通过常量值根据类型显示。
p
占位符应显示为_
字符。对于特定类型
b
(bool) — 显示为true
或false
。c
(char) — 以 Rust 字符形式显示字符(例如'A'
或'\n'
)。- 整数 — 显示整数(以十进制或十六进制显示)。
示例
fn main() { example::<0x12345678>(); } pub fn example<const N: u64>() {}
函数
example
的符号是_RINvCs7qp2U7fqm6G_7mycrate7exampleKy12345678_EB2_ ││└───┬───┘ ││ │ ││ └── const-data 0x12345678 │└─────── const type u64 └──────── const generic arg
建议的反向解析:
mycrate::example::<305419896>
占位符
在类型或常量值不相关的情况下,可能会出现占位符。
示例
pub struct Example<T, const N: usize>([T; N]); impl<T, const N: usize> Example<T, N> { pub fn foo() -> &'static () { static EXAMPLE_STATIC: () = (); &EXAMPLE_STATIC } }
在此示例中,静态变量
EXAMPLE_STATIC
不会通过类型或常量参数T
和N
进行单态化。它们将对这些泛型参数使用占位符。它的符号是_RNvNvMCsd9PVOYlP1UU_7mycrateINtB4_7ExamplepKpE3foo14EXAMPLE_STATIC │ │││ │ ││└── const placeholder │ │└─── const generic argument │ └──── type placeholder └────────────────── generic-args
建议的反向解析:
<mycrate::Example<_, _>>::foo::EXAMPLE_STATIC
类型
type →
basic-type
| 数组类型
| 切片类型
| 元组类型
| 引用类型
| 可变引用类型
| 常量指针类型
| 可变指针类型
| 函数类型
| 动态 trait 类型
| 路径
| 反向引用
类型表示 Rust 类型。初始字符可用于区分编码的类型。基于初始标签字符的类型编码是
- 基本类型 编码为单个字符
a
—i8
b
—bool
c
—char
d
—f64
e
—str
f
—f32
h
—u8
i
—isize
j
—usize
l
—i32
m
—u32
n
—i128
o
—u128
s
—i16
t
—u16
u
— unit()
v
— variadic...
x
—i64
y
—u64
z
—!
p
— 占位符_
其余基本类型编码为 crate 产生式,例如 C4f128
。
-
A
— 一个数组[T; N]
。 -
S
— 一个切片[T]
。切片类型 →
S
类型标签
S
后面跟着切片的 类型。 -
T
— 一个元组(T1, T2, T3, ...)
。元组类型 →
T
{类型}E
标签
T
后面跟着一个或多个 类型,表示每个字段的类型,最后以终止符E
结尾。注意,零长度元组(单元)使用
u
基本类型 进行编码。 -
R
— 一个引用&T
。 -
Q
— 一个可变引用&mut T
。 -
P
— 一个常量原始指针*const T
。标签
P
后面跟着指针的 类型。常量指针类型 →
P
类型 -
O
— 一个可变原始指针*mut T
。可变指针类型 →
O
类型标签
O
后面跟着指针的 类型。 -
F
— 一个函数指针fn(…) -> …
。函数类型 →
F
函数签名函数签名 → 绑定器可选
U
可选 (K
ABI)可选 {类型}E
类型ABI →
C
| 未歧义标识符标签
F
后面跟着函数签名的 函数签名。函数签名是函数指针的签名。它以一个可选的 绑定器 开始,该绑定器表示高阶特征绑定 (
for<…>
)。之后是一个可选的
U
字符,它表示unsafe
函数。之后是一个可选的
K
字符,它表示指定了 ABI。如果未指定 ABI,则假定为"Rust"
ABI。ABI 可以是字母
C
,表示它是"C"
ABI。否则,它是 ABI 字符串的 未歧义标识符,其中破折号转换为下划线。之后是零个或多个 类型,表示函数的输入参数。
之后是字符
E
,然后是返回值的 类型。
-
D
— 一个特征对象dyn Trait<Assoc=X> + Send + 'a
。标签
D
后面跟着一个 动态边界,它编码特征边界,然后是特征对象生命周期绑定的 生命周期。动态边界以一个可选的 绑定器 开始,该绑定器表示高阶特征绑定 (
for<…>
)。之后是由字符E
终止的 动态特征 序列。
推荐的反修饰
一个 类型 可以使用典型的 Rust 语法显示为它表示的类型。
示例
fn main() { example::<[u16; 8]>(); } pub fn example<T>() {}
函数
example
的符号是_RINvCs7qp2U7fqm6G_7mycrate7exampleAtj8_EB2_ │││├┘│ ││││ └─── end of generic args │││└───── const data 8 ││└────── const type usize │└─────── array element type u16 └──────── array type
推荐的解构:
mycrate::example::<[u16; 8]>
绑定器
绑定器 →
G
base-62 数字
一个 *绑定器* 表示要绑定的高阶特征绑定生命周期的数量。它由字符 G
后跟一个 base-62 数字 组成。解码时应将值 1 添加到 base-62 数字(使得 _
的 base-62 数字 编码被解释为具有 1 个绑定器)。
一个 *生命周期* 规则然后可以引用这些编号的生命周期。最小的索引表示最内部的生命周期。绑定生命周期的数量是 base-62 数字 的值加一。
例如,在 for<'a, 'b> fn(for<'c> fn (...))
中,...
中的任何 生命周期(但不在更多的绑定器内部)将观察到索引 1、2 和 3 分别引用 'c
、'b
和 'a
。
推荐的反修饰
反向引用
反向引用 →
B
base-62 数字
一个 *反向引用* 用于引用被 mangled 符号的先前部分。这提供了一种简单的压缩形式,以减少被 mangled 符号的长度。这有助于减少编译器、链接器和加载器所需的工作量和资源。
它由字符 B
后跟一个 base-62 数字 组成。该数字表示从符号的 _R
前缀之后开始的基于 0 的字节偏移量。反向引用表示从该位置开始的相应元素。
反向引用始终引用在 反向引用 本身之前的位置。
反向引用 压缩依赖于这样一个事实,即所有可替换的符号元素都具有自终止的 mangled 形式。给定编码节点的起始位置,语法保证节点在哪里结束始终是明确的。这是通过不允许可替换产生式末尾的可选或重复元素来确保的。
推荐的反修饰
应通过呈现它指向的元素来解构 反向引用。处理深度嵌套的反向引用时应考虑避免使用过多的堆栈。
示例
fn main() { example::<Example, Example>(); } struct Example; pub fn example<T, U>() {}
函数
example
的符号是_RINvCs7qp2U7fqm6G_7mycrate7exampleNtB2_7ExampleBw_EB2_ │├┘ │├┘ │├┘ ││ ││ ││ ││ ││ │└── backref to offset 3 (crate-root) ││ ││ └─── backref for instantiating-crate path ││ │└────── backref to offset 33 (path to Example) ││ └─────── backref for second generic-arg │└───────────────── backref to offset 3 (crate-root) └────────────────── backref for first generic-arg (first segment of Example path)
推荐的解构:
mycrate::example::<mycrate::Example, mycrate::Example>
实例化 crate
实例化-crate → 路径
实例化-crate 是 符号名称 的一个可选元素,可用于指示哪个 crate 正在实例化该符号。它由单个 路径 组成。
这有助于区分否则将相同的符号,例如,如果另一个 crate 也使用相同的类型实例化相同的泛型函数,则外部 crate 中函数的单态化可能会导致重复。
在实践中,实例化 crate 通常也是定义符号的 crate,因此它通常被编码为指向符号中其他位置编码的 crate 根目录 的 反向引用。
推荐的反修饰
实例化-crate 通常不需要显示。
示例
std::path::Path::new("example");
从
mycrate
crate 实例化的Path::new::<str>
的符号是_RINvMsY_NtCseXNvpPnDBDp_3std4pathNtB6_4Path3neweECs7qp2U7fqm6G_7mycrate └──┬───┘ │ └── instantiating crate identifier `mycrate`
推荐的解构:
<std::path::Path>::new::<str>
特定于供应商的后缀
特定于供应商的后缀 → (
.
|$
) 后缀后缀 → {字节}
特定于供应商的后缀 是 符号名称 末尾的可选元素。它由一个 .
或 $
字符后跟零个或多个字节组成。句点或美元符号后的字符没有限制。
此后缀根据实现需要添加。一个可能发生这种情况的示例是当本地唯一名称需要变为全局唯一名称时。LLVM 可以在 LTO 期间附加一个 .llvm.<numbers>
后缀以确保唯一的名称,并且 $
可用于 Mach-O 上的线程本地数据。在这些情况下,通常可以忽略后缀;带后缀的名称与原始名称具有相同的语义。
推荐的反修饰
特定于供应商的后缀 通常不需要显示。
示例
use std::cell::RefCell; thread_local! { pub static EXAMPLE: RefCell<u32> = RefCell::new(1); }
macOS 上
EXAMPLE
的符号可能具有以下线程本地数据_RNvNvNvCs7qp2U7fqm6G_7mycrate7EXAMPLE7___getit5___KEY$tlv$init └───┬───┘ │ └── vendor-specific-suffix
推荐的解构:
mycrate::EXAMPLE::__getit::__KEY
通用规则
非零数字 →
1
|2
|3
|4
|5
|6
|7
|8
|9
数字 →0
| 非零数字小写字母 →
a
|b
|c
|d
|e
|f
|g
|h
|i
|j
|k
|l
|m
|n
|o
|p
|q
|r
|s
|t
|u
|v
|w
|x
|y
|z
大写字母 →
A
|B
|C
|D
|E
|F
|G
|H
|I
|J
|K
|L
|M
|N
|O
|P
|Q
|R
|S
|T
|U
|V
|W
|X
|Y
|Z
十进制数 被编码为一个或多个 数字,表示十进制的数值。
值零被编码为单个字节 0
。请注意,在某些情况下,0
后面可能会跟另一个数字,该数字不应被解码为十进制数字的一部分。例如,一个零长度的标识符在一个嵌套路径内,而该嵌套路径又在另一个嵌套路径内,将导致连续出现两个标识符,其中第一个标识符只有 0
的编码。
数字是一个 ASCII 数字。
小写字母和大写字母分别是 ASCII 小写字母和大写字母。
base-62-number
base-62-number → { 数字 | 小写字母 | 大写字母 }
_
base-62-number 是一个数值的编码。它使用 ASCII 数字、小写字母和大写字母。该值以 _
字符结尾。如果该值为 0,则编码是 _
字符,没有任何数字。否则,从该值中减 1,并使用以下映射进行编码
0
-9
映射到 0-9a
-z
映射到 10 到 35A
-Z
映射到 36 到 61
该数字被反复除以 62(整数除法向零舍入),以选择序列中的下一个字符。每次除法的余数用于映射以选择下一个字符。重复此过程,直到数字为 0。然后反转最终的字符序列。
解码是一个类似的反向过程。
示例
值 | 编码 |
---|---|
0 | _ |
1 | 0_ |
11 | a_ |
62 | Z_ |
63 | 10_ |
1000 | g7_ |
符号语法总结
以下是符号语法所有产生的总结。
symbol-name →
_R
十进制数字opt 路径 实例化 crateopt 供应商特定后缀opt路径 →
箱根
| 固有实现
| 特征实现
| 特征定义
| 嵌套路径
| 泛型参数
| 反向引用crate-root →
C
标识符
inherent-impl →M
impl-path 类型
trait-impl →X
impl-path 类型 路径
trait-definition →Y
类型 路径
nested-path →N
命名空间 路径 标识符
generic-args →I
路径 {generic-arg}E
标识符 → 消歧符opt 未消歧标识符
未消歧标识符 →u
opt 十进制数字_
opt 字节
字节 → {UTF-8 字节}消歧符 →
s
base-62-number类型 →
basic-type
| 数组类型
| 切片类型
| 元组类型
| 引用类型
| 可变引用类型
| 常量指针类型
| 可变指针类型
| 函数类型
| 动态 trait 类型
| 路径
| 反向引用基本类型 → 小写字母
数组类型 →A
类型 常量
切片类型 →S
类型
元组类型 →T
{类型}E
引用类型 →R
生命周期opt 类型
可变引用类型 →Q
生命周期opt 类型
常量指针类型 →P
类型
可变指针类型 →O
类型
函数类型 →F
函数签名
动态 trait 类型 →D
动态边界 生命周期generic-arg →
lifetime
| 类型
|K
常量生命周期 →
L
base-62-number十六进制数字 → 数字 |
a
|b
|c
|d
|e
|f
函数签名 → 绑定器opt
U
opt (K
ABI)opt {类型}E
类型动态边界 → 绑定器opt {动态 trait}
E
动态 trait → 路径 {动态 trait 关联绑定}
动态 trait 关联绑定 →p
未消歧标识符 类型绑定器 →
G
base-62-number后向引用 →
B
base-62-number供应商特定后缀 → (
.
|$
) 后缀
后缀 → {字节}base-62-number → { 数字 | 小写字母 | 大写字母 }
_
非零数字 →
1
|2
|3
|4
|5
|6
|7
|8
|9
数字 →0
| 非零数字
小写字母 →a
|b
|c
|d
|e
|f
|g
|h
|i
|j
|k
|l
|m
|n
|o
|p
|q
|r
|s
|t
|u
|v
|w
|x
|y
|z
大写字母 →A
|B
|C
|D
|E
|F
|G
|H
|I
|J
|K
|L
|M
|N
|O
|P
|Q
|R
|S
|T
|U
|V
|W
|X
|Y
|Z
Rust 实体的编码
以下是在符号中如何编码 Rust 实体的指导原则。只要符号是明确的,编译器在如何编码实体方面有一定的自由度。
-
命名的函数、方法和静态变量应由一个路径产生式表示。
-
路径应该以可以充当路径根的最内层实体为根。根可以是 crate-id、固有 impl、trait impl 和(对于默认方法中的项)trait 定义。
-
编译器可以从保留范围中选择消歧索引和命名空间标签,只要它确定标识符的明确性。
-
等于默认值的泛型参数为了节省空间不应进行编码。