13 个版本 (8 个稳定版)
1.2.0 | 2024 年 5 月 7 日 |
---|---|
1.1.5 | 2022 年 11 月 12 日 |
1.1.4 | 2022 年 6 月 4 日 |
1.1.3 | 2022 年 1 月 2 日 |
0.2.3 | 2020 年 9 月 6 日 |
#7 in 内存管理
每月 234,803 次下载
用于 73 个 Crates(直接使用 41 个)
105KB
1.5K SLoC
arcstr
: 更好的引用计数字符串。
此 crate 定义了 ArcStr
,一个引用计数字符串类型。它本质上试图成为一个更好的 Arc<str>
或 Arc<String>
,至少对于大多数用例。
ArcStr 故意放弃了 Arc
中一些很少使用的功能,例如 Weak
、Arc::make_mut
等。作为交换,它获得了许多非常有用的功能,特别是对字符串。特别是对便宜/无成本的 ArcStr
持有静态数据(例如,字符串字面量)的强大支持。
(除此之外,它还是单指针,这可以提高性能和 FFI)
此外,如果启用了 substr
功能(默认情况下是启用的),我们提供了一个 Substr
类型,它本质上是一个 (ArcStr, Range<usize>)
,具有更好的易用性和更多功能,它表示一个“父” ArcStr
的共享切片(请注意,实际上使用 u32
作为索引类型,但此 API 中未暴露,可以通过 cargo 功能透明地更改)。
功能概述
快速浏览ArcStr的独特特性(注意,在ArcStr的[文档](https://docs.rs/arcstr/%2a/arcstr/struct.ArcStr.html#benefits-of-arcstr-over-arcstr)中有一个关于ArcStr相对于其他替代方案的[优势列表](https://docs.rs/arcstr/%2a/arcstr/struct.ArcStr.html#benefits-of-arcstr-over-arcstr),其中涵盖了一些你可能希望使用它的原因)。注意,它提供了您可能从不可变字符串类型期望的几乎所有字符串-like功能——这些只是独特的卖点。
use arcstr::ArcStr;
// Works in const:
const AMAZING: ArcStr = arcstr::literal!("amazing constant");
assert_eq!(AMAZING, "amazing constant");
// `arcstr::literal!` input can come from `include_str!` too:
const MY_BEST_FILES: ArcStr = arcstr::literal!(include_str!("my-best-files.txt"));
或者,您可以在普通表达式中定义字面量。注意,这些字面量本质上属于"零成本"。具体来说,以下我们不仅没有为实例化wow
或任何克隆分配堆内存,而且在克隆、丢弃(或在任何其他操作它们的过程中)时也不需要进行任何原子读取或写入。
let wow: ArcStr = arcstr::literal!("Wow!");
assert_eq!("Wow!", wow);
// This line is probably not something you want to do regularly,
// but as mentioned, causes no extra allocations, nor performs any
// atomic loads, stores, rmws, etc.
let wowzers = wow.clone().clone().clone().clone();
// At some point in the future, we can get a `&'static str` out of one
// of the literal `ArcStr`s too.
let static_str: Option<&'static str> = ArcStr::as_static(&wowzers);
assert_eq!(static_str, Some("Wow!"));
// Note that this returns `None` for dynamically allocated `ArcStr`:
let dynamic_arc = ArcStr::from(format!("cool {}", 123));
assert_eq!(ArcStr::as_static(&dynamic_arc), None);
待办事项:在此处包含Substr
的使用,因为它也有一些令人信服的应用场景!
用法
它是一个普通的Rust包,将其添加到您的Cargo.toml
的依赖项部分。在您不太可能在这里的情况下,不知道如何操作
[dependencies]
# ...
arcstr = { version = "...", features = ["..."] }
以下是一些可用的Cargo功能。目前默认启用的是substr
。
-
std
(默认关闭):启用后,将使用std::process
的终止,而不是使用“双重panic技巧”触发终止。基本上,我们需要终止的一种情况是在发生灾难性错误时,您泄露了相同的(动态)
ArcStr
(在32位系统上为2^31,在64位系统上为2^63)。如果发生这种情况,我们将遵循libstd
的先例并直接终止,因为我们已经陷入困境。如果启用了std
,我们将使用真实的std::process::abort
。如果未启用std
,我们将通过在另一个panic正在展开时触发panic来触发abort
,这要么被定义为导致终止,要么在实践中导致终止。实际上,您永远也不会遇到这种边缘情况,而且它仍在no_std中正常工作,因此no_std是默认设置。如果您必须将其启用,因为您遇到了这种情况并且发现我们的处理不好,请让我知道。
具体来说,这里的区别是,如果没有这个,这个情况将变成对
core::intrinsics::abort
的调用,而不是对std::process::abort
的调用。这是一个极不可能遇到的边缘情况,但如果您遇到了,使用std::process::abort
将导致SIGABRT
,而使用core::intrinsics::abort
将导致SIGILL
,前者具有明显更好的用户体验。话虽如此,您成功泄露2^31
或2^63
个相同的ArcStr
副本的可能性极低,因此我们认为默认情况下依赖std
并不是很有必要。 -
serde
(默认关闭):启用ArcStr
的serde序列化。请注意,这不会执行任何复杂的去重或其他操作。 -
substr
(默认开启):实现Substr
类型和相关函数。 -
substr-usize-indices
(默认关闭,隐含substr
):底层使用usize
作为边界,而不是u32
。如果没有这个,如果你使用
Substr
并且索引会溢出u32
,我们会毫不犹豫地 panic。
unsafe
的使用和测试策略
虽然这个crate包含相当数量的 unsafe 代码,但我们有以下几点理由来证明这一点:
- 我们拥有非常高的测试覆盖率(基本上唯一未覆盖的函数是内存不足处理程序(它只是调用
alloc::handle_alloc_error
)和一个极端的整数溢出,我们只是直接终止程序)。 - 所有测试在各种 sanitizers 下都通过:
asan
、msan
、tsan
和miri
。 - 我们有一些
loom
模型,尽管我希望有更多。 - 我们的测试在各种不同的目标上通过(多亏了
cross
的许多可能——甚至简单易行)- Linux x86、x86_64、armv7(arm32)、aarch64(arm64)、riscv64、mips32 和 mips64(mips32 和 mips64 目标允许我们检查大端 32 位和 64 位。尽管我们目前没有特定于字节序的代码)。
- Windows 32 位和 64 位,在 GNU 和 MSVC 工具链上。
- MacOS 在 x86_64 上。
此外,我们在 Rust stable、beta、nightly 和我们的 MSRV(见上方的徽章以了解 MSRV)上进行了测试。
支持的平台
请注意,上述内容 不是 支持的平台列表。一般来说,我预计 arcstr
将支持所有平台上的 Rust,除了那些具有 target_pointer_width="16"
的平台,如果关闭 substr
功能,它们应该可以工作。话虽如此,如果您希望我将平台添加到 CI 覆盖范围以确保它不会崩溃,请随时告诉我(尽管,如果它比添加另一个 cross
目标更困难,我可能需要您证明它不太可能被现有的平台测试覆盖)。
* 这就是为什么有 riscv64 的原因。
依赖项
~170KB