本文档列出了在 Fuchsia 源代码树中编写 Rust 时要遵循的规范。这些惯例结合了最佳做法、项目偏好以及为保持一致而做出的一些选择。
指南
命名
大小写符合 Rust 的习语
请参阅 C-CASE。
临时转化遵循 as_
、to_
、into_
规范
请参阅 C-CONV。
getter 名称遵循 Rust 惯例
除了少数例外情况,Rust 代码中的 getter 不使用 get_
前缀。
请参阅 C-GETTER。
生成迭代器的集合中的方法遵循 iter
、iter_mut
、into_iter
请参阅 C-ITER。
迭代器类型名称与生成迭代器类型的方法一致
请参阅 C-ITER-TY。
名称使用一致的字词顺序
请参阅 C-WORD-ORDER。
互操作性
类型急于实现常见 trait
Copy
、Clone
、Eq
、PartialEq
、Ord
、PartialOrd
、Hash
、Debug
、Display
和 Default
都应适时实现。
请参阅 C-COMMON-TRAITS。
转化使用标准特征 From
、AsRef
、AsMut
请参阅 C-CONV-TRAITS。
集合实现了 FromIterator
和 Extend
请参阅 C-COLLECT。
数据结构实现了 Serde 的 Serialize
和 Deserialize
请参阅 C-SERDE。
尽可能类型为 Send
和 Sync
请参阅 C-SEND-SYNC。
错误类型有意义且表现良好
请参阅 C-GOOD-ERR。
二进制数字类型提供 Hex
、Octal
和 Binary
格式
请参阅 C-NUM-FMT。
通用读取器/写入器函数按值接受 R: Read
和 W: Write
请参阅 C-RW-VALUE。
宏
输入语法可调用输出
请参阅 C-EVOCATIVE。
宏通过属性组合起到很好的效果
请参阅 C-MACRO-ATTR。
内容宏可以在允许使用内容的所有位置使用
请参阅 C-ANYWHERE。
商品宏支持可见性说明符
请参阅 C-MACRO-VIS。
类型 fragment 很灵活
请参阅 C-MACRO-TY。
文档
crate 级别文档非常全面,并提供了示例
请参阅 C-CRATE-DOC。
所有项都有一个 rustdoc 示例
请参阅 C-EXAMPLE。
<ph type="x-smartling-placeholder"></ph>
示例使用 ?
,而不是 try!
,而不是 unwrap
请参阅 C-QUESTION-MARK。
函数文档包括错误、紧急警报和安全注意事项
请参阅 C-FAILURE。
散文包含指向相关内容的超链接
请参阅 C-LINK。
Rustdoc 未显示无用的实现详情
请参阅 C-HIDDEN。
每个 unsafe
块都有相应的理由
安全理由应以 // SAFETY:
开头,并解释为什么不安全的代码块是合理的。
正确做法
// SAFETY: <why this unsafe operation's safety requirements are met>
错误做法
// Safety: <...>
// [SAFETY] <...>
// <...>
// SAFETY: Trust me.
不安全代码应说明为什么需要不安全代码块,以及 是声音。如果有看起来可能适用但无法使用的安全替代方案, 以及不可使用的原因。
正确做法
// SAFETY: The `bytes` returned from our string builder are guaranteed to be
// valid UTF-8. We used to call `from_utf8`, but this caused performance issues
// with large inputs.
let s = unsafe { String::from_utf8_unchecked(bytes) };
错误做法
// SAFETY: We shouldn't have to validate `bytes`, and the safe version is slow.
let s = unsafe { String::from_utf8_unchecked(bytes) };
理由应直接指明操作的要求。可以概括为 但前提是所有要求得到满足。
正确做法
// SAFETY: The caller has guaranteed that `ptr` is valid for reads, properly
// aligned, and points to a properly-initialized `T`.
unsafe {
let x = ptr.read();
}
正确做法
// SAFETY: The caller has guaranteed that `ptr` points to a valid `T`.
unsafe {
let x = ptr.read();
}
错误做法
// SAFETY: `ptr` is safe to read.
unsafe {
let x = ptr.read();
}
安全理由应说明为什么操作合理,而不仅仅是操作 理由。
正确做法
const BUFFER_LEN: usize = 1024;
fn partially_init(n: usize) -> MaybeUninit<[i32; BUFFER_LEN]> {
// These asserts ensure our safety conditions are met later on
const _: () = assert!(BUFFER_LEN <= 1024);
assert!(n < BUFFER_LEN);
let mut buffer = MaybeUninit::<[i32; BUFFER_LEN]>::uninit();
let ptr = buffer.as_mut_ptr().cast::<i32>();
for i in 0..n {
// SAFETY:
// - `ptr` points to the first `i32` of `buffer`.
// - `buffer` has space for BUFFER_LEN elements and we asserted that
// `n < BUFFER_LEN`.
// - We asserted that `BUFFER_LEN <= 1024`, so `size_of::<i32>() * i`
// is at most 4096 which is less than `isize::MAX` and `usize::MAX`.
let element = unsafe { &mut *ptr.add(i) };
*element = i as i32;
}
buffer
}
错误做法
const BUFFER_LEN: usize = 1024;
fn partially_init(n: usize) -> MaybeUninit<[i32; BUFFER_LEN]> {
// Why are these asserts here?
const _: () = assert!(BUFFER_LEN <= 1024);
assert!(n < BUFFER_LEN);
let mut buffer = MaybeUninit::<[i32; BUFFER_LEN]>::uninit();
let ptr = buffer.as_mut_ptr().cast::<i32>();
for i in 0..n {
// SAFETY:
// - `ptr` is in bounds or one byte past the end of an allocated object.
// - `ptr + i` is also in bounds.
// - The computed offset, in bytes, doesn't overflow an `isize`.
// - The offset being in bounds does not rely on "wrapping around" the
// address space.
let element = unsafe { &mut*ptr.add(i) };
*element = i as i32;
}
buffer
}
不安全的 trait 已记录,不安全的 trait 实现是合理的
不安全特征应按照与不安全函数相同的准则来记录。
不安全特征定义应记录安全注意事项(请参阅 C-FAILURE),以及
不安全的 trait 实现应该是合理的(请参阅
“每个 unsafe
块都有相应的理由”))
正确做法
/// A labeler that always returns unique labels.
///
/// # Safety
///
/// Every time `create_unique_label()` is called on the same labeler, it must
/// return a distinct `u32`.
unsafe trait UniqueLabeler {
/// Returns a new unique label.
fn create_unique_label(&mut self) -> u32;
}
struct SequentialLabeler {
next: Option<u32>,
}
// SAFETY: `create_unique_label()` will always return the next sequential label
// or panic if all available labels are exhausted.
unsafe impl UniqueLabeler for SequentialLabeler {
fn create_unique_label(&mut self) -> u32 {
if let Some(next) = self.next {
self.next = (next < u32::MAX).then(|| next + 1);
next
} else {
panic!("sequential unique labels exhausted");
}
}
}
错误做法
/// A labeler that always returns unique labels.
unsafe trait UniqueLabeler {
/// Returns a new unique label.
fn create_unique_label(&mut self) -> u32;
}
struct SequentialLabeler {
next: u32,
}
unsafe impl UniqueLabeler for SequentialLabeler {
fn create_unique_label(&mut self) -> u32 {
// This will have correct panicking behavior in debug builds because
// integer overflow is trapped. In a release build, this will still
// overflow but our labeler will not panic!
let result = self.next;
next += 1;
result
}
}
不安全的操作始终位于 unsafe
块中
在 Fuchsia 中,unsafe
函数不会被视为不安全的上下文。必须始终确保
位于 unsafe
代码块内,即使位于 unsafe
函数正文中也是如此。
正确做法
unsafe fn clear_slice(ptr: *mut i32, len: usize) {
assert!(len.checked_mul(mem::size_of::<i32>()).unwrap() < isize::MAX);
// SAFETY:
// - The caller has guaranteed that `ptr` points to `len` consecutive, valid
// i32s and that the data at behind `ptr` is not simultaneously accessed
// through any other pointer.
// - We asserted that the total size of the slice is less than isize::MAX.
let slice = unsafe { slice::from_raw_parts_mut(ptr, len) };
for x in slice.iter_mut() {
*x = 0;
}
}
错误做法
unsafe fn clear_slice(ptr: *mut i32, len: usize) {
// We forgot to assert that the length of the slice is less than isize::MAX!
// If we justified our call to from_raw_parts_mut, we would have been much
// more likely to remember.
let slice = slice::from_raw_parts_mut(ptr, len);
for x in slice.iter_mut() {
*x = 0;
}
}
可预测性
智能指针不会添加固有方法
请参阅 C-SMART-PTR。
系统会根据所涉及的最具体的类型实时显示转化
请参阅 C-CONV-SPECIFIC
具有明确接收器的函数是方法
请参阅 C-METHOD。
函数不取出形参
请参阅 C-NO-OUT。
运算符过载并不奇怪
请参阅 C-OVERLOAD。
只有智能指针会实现 Deref
和 DerefMut
请参阅 C-DEREF。
构造函数是静态的固有方法
请参阅 C-CTOR。
灵活应对
函数公开中间结果以避免重复工作
请参阅 C-INTERMEDIATE。
调用方决定在哪里复制和放置数据
请参阅 C-CALLER-CONTROL。
函数使用泛型尽可能减少对参数的假设
请参阅 C-GENERIC。
如果特征作为 trait 对象有用,则它们是对象安全的
请参阅 C-OBJECT。
类型安全
新类型提供静态区别
请参阅 C-NEWTYPE。
参数通过类型(而不是 bool
或 Option
)传达含义
请参阅 C-CUSTOM-TYPE。
一组标志的类型是 bitflags
,而不是枚举
请参阅 C-BITFLAG。
构建器支持构建复杂值
请参阅 C-BUILDER。
可靠性
函数验证其参数
请参阅 C-VALIDATE。
析构函数始终不会失败
请参阅 C-DTOR-FAIL。
可能阻塞的析构函数有替代函数
请参阅 C-DTOR-BLOCK。
可调试性
所有公共类型都会实现 Debug
请参阅 C-DEBUG。
Debug
表示法永不为空
请参阅 C-DEBUG-NONEMPTY。
满足未来需求
密封特征可防止下游实现
请参阅 C-SEALED。
结构体具有私有字段
请参阅 C-STRUCT-PRIVATE。
Newtype 封装了实现详情
请参阅 C-NEWTYPE-HIDE。
数据结构不会复制派生的特征边界
请参阅 C-STRUCT-BOUNDS。
更新指南
要建议添加或修改,请打开 CL 并抄送
fuchsia-rust-api-rubric@google.com
以确保审核通过。使用任意值
以便对提案进行迭代改进。
在反馈得到解决后,该文件的所有者中
而提案作者则不能作为协调员,将提案移到最后
调用。辅导员会向 fuchsia-rust-api-rubric@google.com
发送电子邮件
宣布上一次提案通话此提案将开放反馈意见
期限为 7 个日历日。
在上一个通话周期结束时,且在解决相关问题之后 辅导员将对 CL 作出评论,最后 并据此做出决定。任何有争议的内容 就相关问题做出充分的公开讨论后做出决定, 并在 CL 注释中提供理由。决策结果应 也会发送到电子邮件会话
如果提案被接受,辅导员会留下 +2,而作者可以 然后提交
待定主题
待处理的主题会在 Rust 问题跟踪器组件中进行跟踪。
与上游 Rust API 指南的关系
此评分准则包含 Rust API 指南的大部分内容,但以下内容 官方准则:
- C-FEATURE,因为 Fuchsia 并不 目前支持 crate 功能。
- C-METADATA(作为 Fuchsia)
不维护内部
Cargo.toml
文件。 - C-HTML-ROOT,如下所示
Fuchsia 目前没有将大多数 Rust 代码发布到
crates.io
。 - C-RELNOTES Fuchsia 中的 Rust 代码“位于 HEAD”。
- C-STABLE,就像 Fuchsia 所做的那样
目前未将大多数 Rust 代码发布到
crates.io
。 - C-PERMISSIVE 作为所有 Fuchsia 的 Rust 代码受 Fuchsia 许可。
以下是特定于 Fuchsia 的指南: