#memory-safety #wrapper #drop

no-std no_drop

A simple wrapper type that guards against a value being automatically dropped

5 unstable releases

Uses new Rust 2024

0.4.1 Jan 31, 2026
0.4.0 Jan 31, 2026
0.3.0 Jan 12, 2026
0.2.3 Dec 18, 2025
0.2.2 Dec 18, 2025

#779 in Rust patterns

42 downloads per month
Used in collect_failable

MIT/Apache

37KB
566 lines

no_drop

Build Docs Crates.io dependency status codecov GitHub License

A selection of guard types that guard against values being automatically dropped, ensuring a value is explicitly consumed.

Features

  • NoDrop and NoDropMsg - Wraps a value in a guard type to ensure it is explicitly consumed before the guard is dropped.
  • DropGuard and DropGuardMsg - A mutable drop guard that can be dynamically armed and disarmed.
  • dbg and rls modules - identical API, provide panic protection in debug mode only or in all builds respectively.

Install

It's on crates.io.

Usage - NoDrop and NoDropMsg

Wrap a value in a guard type to ensure it is explicitly consumed before the guard is dropped.

use no_drop::rls::NoDrop;

let value = NoDrop::wrap(42);

// Extract the value safely
let inner = value.unwrap();
assert_eq!(inner, 42);

let value = NoDrop::wrap(43);
drop(value); // panic: "Value was dropped without being unwrapped"

For more descriptive error messages, use NoDropMsg with custom panic messages:

use no_drop::rls::NoDropMsg;
// msg can be an owned or borrowed value
let value = NoDropMsg::wrap(42, "forgot to process the answer");

drop(value); // panic: "forgot to process the answer"

Using as a Drop Guard

NoDrop and NoDropMsg support using unit type () instances, allowing you to use them as drop guards within another type, to ensure a specific method is called before the type is dropped. This can be useful to enforce a manual RAII pattern or to enforce a builder pattern.

use no_drop::rls::NoDrop;

#[derive(Debug, Default)] // NoDrop implements Default and Debug
struct Transaction {
    guard: NoDrop,
    other_data: i32,
}

impl Transaction {
    fn new(x: i32) -> Self {
        Self { guard: NoDrop::guard(), other_data: x }
    }

    fn finalize(self) {
        // do necessary finalization work
        self.guard.forget(); // Disarm the guard by consuming it
    }
}

let t = Transaction::new(10);
// do work.
t.finalize();
// Dropping without calling `finalize()` would panic.

For custom panic messages with drop guards, use NoDropMsg::guard

Usage - DropGuard and DropGuardMsg

Unlike NoDrop types, which are consumed when unwrapped, DropGuards can be dynamically armed and disarmed. This makes them ideal for protecting mutable state or critical sections that may be entered and exited, possibly multiple times.

use no_drop::rls::DropGuard;

let mut guard = DropGuard::new_armed("critical section not exited properly");

// Check state
assert!(guard.is_armed());

// do work...

// Safely exit critical section
guard.disarm();

// Can rearm if needed
guard.arm();
guard.disarm(); // Message is retained across arm/disarm cycles

For cases where you don't need a custom panic message, use DropGuardEmpty, which provides the same arm/disarm functionality with a default panic message

Debug vs Release Variants

NoDrop, NoDropMsg, DropGuard, DropGuardEmpty have debug-only and always-panicking variants:

Dependencies

~230–670KB
~14K SLoC