2个版本
0.1.1 | 2023年5月24日 |
---|---|
0.1.0 | 2023年5月24日 |
#1338 在 Rust模式
3,953 每月下载量
用于 drop_arena
17KB
276 代码行
consume_on_drop
一个零成本的抽象,允许通过值来消耗Drop::drop中的self
你想要在impl Drop时以值的形式调用函数吗?你需要同时解构和丢弃你的结构体吗?你想要一个方便的类型来临时为你的值提供一个新的Drop实现吗?这个crate就是为你准备的。
安全、零成本API
ConsumeOnDrop<T>
是围绕T
的一个透明包装器,所有提供的操作都是零成本的。
WithConsumer<T, Q>
是一个有序对(T, Q)
的包装器,其所有提供的操作都是零成本的。
这些API中的所有公共函数、方法和特性都是完全安全的。
使用最少的unsafe
代码实现
ConsumeOnDrop
的实现恰好有2行unsafe
代码,都很容易通过Miri检查和测试。
WithConsumer
的实现完全安全(除了它依赖于ConsumeOnDrop
的公共API之外)。
在丢弃时以值的形式消耗你的类型
use consume_on_drop::{Consume, ConsumeOnDrop, WithConsumer};
struct T;
fn consume_t(_t: T) {
println!("We consumed T")
}
impl Consume for T {
fn consume(self) {
consume_t(self)
}
}
fn main () {
let t = ConsumeOnDrop::new(T); // A thin wrapper around T which calls T::consume on drop
drop(t);
let t = WithConsumer::new(T, consume_t); // Alternately, we can explicitly equip a T with a consumer.
drop(t);
}
编写一个可以解构和丢弃的结构体
以下代码无法编译。
struct MutRef<'a> {
inner: &'a mut i32,
}
impl<'a> MuRef<'a> {
pub fn new(val: &'a mut i32) -> Self {
Self { inner: val }
}
pub fn into_inner(self) -> &'a mut i32 {
self.inner
}
}
impl<'a> Drop for MutRef<'a> {
fn drop(&mut self) {
*self.inner += 1;
}
}
但我们可以使用ConsumeOnDrop
来使其工作
use consume_on_drop::{Consume, ConsumeOnDrop};
struct RawMut<'a> {
inner: &'a mut i32,
}
impl<'a> Consume for RawMut<'a> {
fn consume(self) {
*self.inner += 1;
}
}
struct MutRef<'a> {
inner: ConsumeOnDrop<RawMut<'a>>,
}
impl<'a> MutRef<'a> {
pub fn new(val: &'a mut i32) -> Self {
Self { inner: ConsumeOnDrop::new(RawMut { inner: val })}
}
pub fn into_inner(self) -> &'a mut i32 {
ConsumeOnDrop::into_inner(self.inner).inner
}
}
请注意,这是一个零成本的抽象。我们可以使用Option<RawMut>
来实现相同的效果,但这会带来运行时开销,并阻止我们使用空指针优化Option<MutRef>
。
暂时给你的类型一个不同的drop实现
有时,你需要暂时给你的类型一个新的drop
实现,以防你提前返回或panic。如果在错误的时间发生panic,数据可能会处于无效状态。为了标记这一点,你可能希望“毒化”你的数据。
use consume_on_drop::WithConsumer;
struct Data {
string: Option<String>,
}
impl Data {
fn new(str: String) -> Self {
Self { string: Some(str) }
}
fn extend(&mut self, str: String) {
self.string.as_mut().unwrap().extend(str.chars())
}
fn poison(&mut self) {
self.string = None;
}
}
fn produce_string() -> String {
panic!("Oh no, we panicked!");
}
fn extend_produce(data: &mut Data) {
let mut data = WithConsumer::new(data, Data::poison);
data.extend(produce_string()); // if produce_string panics, we will drop data here and poison it
WithConsumer::into_inner(data); // but if there's no panic, we will not poison.
}
许可证:MIT许可证