#leak #drop #memory-leaks #cancel #event-listener #cleanup #revoke

discard

Discard trait which allows for intentionally leaking memory

5 stable releases

Uses old Rust 2015

1.0.4 Sep 17, 2018
1.0.3 Feb 25, 2018

#228 in Memory management

Download history 41909/week @ 2023-12-15 23692/week @ 2023-12-22 33375/week @ 2023-12-29 31026/week @ 2024-01-05 34758/week @ 2024-01-12 48322/week @ 2024-01-19 35422/week @ 2024-01-26 43258/week @ 2024-02-02 38698/week @ 2024-02-09 27888/week @ 2024-02-16 34563/week @ 2024-02-23 30618/week @ 2024-03-01 32544/week @ 2024-03-08 35527/week @ 2024-03-15 33033/week @ 2024-03-22 37231/week @ 2024-03-29

144,041 downloads per month
Used in 634 crates (11 directly)

MIT license

14KB
131 lines

Discard trait which allows for intentionally leaking memory.

See the documentation for more details.


lib.rs:

There are situations where you need to intentionally leak some memory but not other memory. This crate can help!

But before I explain, you are probably wondering: why would I want to leak memory in the first place?

There are certain rare situations where leaking memory is either desirable or necessary.

As an example, let's say I am using stdweb, which lets me use JavaScript APIs in Rust.

So I write some code like this:

node.add_event_listener(|event: ClickEvent| {
    // ...
});

Seems reasonable, right? But there's a problem: the add_event_listener method returns an EventListenerHandle, and when the EventListenerHandle is dropped it will remove the event listener.

Because I'm not using the EventListenerHandle, it is immediately dropped, so it receives no events!

Okay, no problem, just use std::mem::forget:

// This will automatically remove the event listener when `handle` is dropped
let handle = node.add_event_listener(|event: ClickEvent| {
    // ...
});

// Now it will no longer remove the event listener
std::mem::forget(handle);

Now the event listener will remain alive forever, which is what I want.

But there's two problems with this:

  1. I want it to keep the event listener alive forever, but I also want it to clean up any unused internal memory. Using std::mem::forget causes it to leak all of the memory, which is wasteful.

  2. There are situations where I want to leak the event listener, and then later unleak it. That's not possible with std::mem::forget.

The solution to all of these problems is:

  1. The EventListenerHandle should not implement the Drop trait.

  2. The EventListenerHandle should implement the Discard trait instead.

  3. The add_event_listener method should return DiscardOnDrop<EventListenerHandle>.

Now let's look at what is possible:

// This will automatically remove the event listener when `handle` is dropped
let handle = node.add_event_listener(|event: ClickEvent| {
    // ...
});

// Now it will no longer remove the event listener, this is similar to `std::mem::forget`
let leaked = DiscardOnDrop::leak(handle);

// Now it will remove the event listener, even though it was leaked
leaked.discard();

There's two huge differences between DiscardOnDrop::leak and std::mem::forget:

  1. std::mem::forget leaks all of the memory, DiscardOnDrop::leak leaks the minimal amount of memory: unused memory is properly cleaned up.

  2. With std::mem::forget you cannot clean up a value after it has been leaked, but with DiscardOnDrop::leak you can manually discard the value even after it has been leaked.

Most of the time you don't need to worry about any of this: DiscardOnDrop will automatically call discard when it is dropped, so in that situation Discard behaves the same as Drop.

So you can use normal Rust idioms, and everything works as you would expect. You only need to worry about Discard when you need to intentionally leak some memory.

No runtime deps