drop_cell

Crates.iodrop_cell
lib.rsdrop_cell
version0.0.0
sourcesrc
created_at2022-12-17 10:42:03.969965
updated_at2022-12-17 10:42:03.969965
descriptionAn alternative way of implementing `Drop`
homepage
repository
max_upload_size
id739754
size15,060
xian (rueyxian)

documentation

README

drop_cell

An alternative way of implementing Drop in Rust.

Overview

This library provides the defer! macro to defer execution until the end of the stack frame.

The defer! macro emulates Golang Defer statements.

defer!(println!("world"));
println!("hello");
return;
println!("unreachable");

Output:

hello
world

Borrowing rules

The following code won't compile.

    let mut v = vec![1, 2];
    defer!(assert_eq!(v, &[1, 2, 3]));
//                    └─ immutable borrow occurs here ──────────┐
    v.push(3); //                                               │
//  └─ mutable borrow occurs here                               │
//                                                              │
// immutable borrow will be used at the end of the stack frame ─┘

We want to run assert_eq!(v, &[1, 2, 3]) at the end of the stack frame, but it breaks the borrowing rules.

To work around, we need to pass v into defer!.

    let v = vec![1, 2];
//      └─ consumes it ─┐
//         ┌────────────┘
    defer!(v => assert_eq!(v, &[1, 2, 3]));        
    v.push(3);

Example

use drop_cell::defer;
use std::io::Write;
use std::sync::mpsc;

fn main() {
    no_arg();
    args();
    bind();
}

fn no_arg() {
    let (tx, rx) = mpsc::channel();
    defer! {
        assert_eq!(rx.recv().unwrap(), "hello");
        assert_eq!(rx.recv().unwrap(), "world");
    };
    tx.send("hello").unwrap();
    tx.send("world").unwrap();
}

fn args() {
    let (v1, v2) = (vec![], vec![]);
    defer! { v1, v2 =>
        assert_eq!(v1, b"hello");
        assert_eq!(v2, b"world");
    }
    write!(v1, "hello").unwrap();
    write!(v2, "world").unwrap();
}

fn bind() {
    let ss = vec![];
    defer! { v @ Some(ss) =>
        let v = v.take().unwrap();
        assert_eq!(v.as_slice(), ["hello", "world"]);
    }
    v.as_mut().unwrap().push("hello");
    v.as_mut().unwrap().push("world");
}

When and when not

When to use
  • When you want a Finalizer but reluctant to create a struct for it.
When NOT to use
  • When RAII pattern is preferable. e.g. Lock and Reference Counting.
  • When the code is written inside a method, using defer! might complicate the code.
Commit count: 0

cargo fmt