Expand description

Purpose

Sometimes it is critical to drop an object as soon as it is no longer used, even before the end of scope. For example: Dropping a MutexGuard to prevent deadlock.

The PipeDrop trait provides methods that allow you to get a reference (immutable or otherwise) to an object, do something with the reference (inside the callback function), and then drop the object.

Exhibit A: Drop order

Given the following code which declare an object that logs its own creation and destruction:

#[derive(Debug)]
struct Object {
    id: usize,
}

impl Default for Object {
    fn default() -> Self {
        println!("create 0");
        Object { id: 0 }
    }
}

impl Drop for Object {
    fn drop(&mut self) {
        println!("drop {}", self.id)
    }
}

impl Clone for Object {
    fn clone(&self) -> Self {
        let id = self.id + 1;
        println!("create {}", id);
        Object { id }
    }
}

The following code would only drop a and b when they are out of scope:

let a = Object::default();
let b = a.clone();
let c = b.clone();
println!("-- end of scope --");

Output:

create 0
create 1
create 2
-- end of scope --
drop 2
drop 1
drop 0

In the above output, the numbers (0, 1, 2) correspond to the variables (a, b, c respectively), and the verbs (create and drop) corresponds to actions (Object::default()/Object::clone() and drop respectively).

In order to force a and b to be dropped before the end of scope, we must explicitly call drop:

let a = Object::default();
let b = a.clone();
drop(a);
let c = b.clone();
drop(b);
println!("-- end of scope --");

Output:

create 0
create 1
drop 0
create 2
drop 1
-- end of scope --
drop 2

As you can see in the output above, both drop 0 and drop 1 were called before -- end of scope --, which means that a and b were dropped before the end of scope.

However, explicitly calling drop makes our code ugly, and quite hard to fit in a dot-chain, we can fix this by using PipeDrop:

use pipe_drop::PipeDrop;
let c = Object::default() // a
    .pipe_ref_drop(Object::clone) // b
    .pipe_ref_drop(Object::clone);
println!("-- end of scope --");

Output:

create 0
create 1
drop 0
create 2
drop 1
-- end of scope --
drop 2

The above output is exactly like when we called drop explicitly!

Traits

Purpose