quick-bool 0.1.0

A lock-free boolean implementation using atomic operations
Documentation
  • Coverage
  • 85.71%
    6 out of 7 items documented4 out of 6 items with examples
  • Size
  • Source code size: 63.72 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.42 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Links
  • jdx/quick-bool
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • jdx

QuickBool

Crates.io docs.rs License: MIT Build Status

A lock-free boolean implementation using atomic operations for high-performance lazy evaluation.

(right now this is experimental and I'm not sure I can actually get it to be faster than LazyLock)

Overview

QuickBool is a lightweight, lock-free alternative to LazyLock<bool> that uses atomic operations instead of mutexes for synchronization. It provides a 3-way boolean state:

  • Unset: The value hasn't been evaluated yet
  • True: The value is true
  • False: The value is false

Once set to true or false, the value cannot be changed, making it effectively immutable after initialization.

Features

  • Lock-free: Uses atomic operations for thread-safe access without locks
  • Zero-cost reads: Once computed, subsequent reads are just atomic loads
  • Single computation: The computation function is guaranteed to execute only once
  • Thread-safe: Safe for concurrent access from multiple threads
  • No dependencies: Pure Rust with no external dependencies
  • Reset capability: Can be reset to allow recomputation if needed

License

MIT License - see LICENSE file for details.

Performance

QuickBool is now the fastest implementation for both first access and cached access, while maintaining all its additional features:

Benchmarks

First Access Performance

xychart-beta
    title "First Access Performance Comparison"
    x-axis "Implementation" ["LazyLock", "OnceLock", "QuickBool"]
    y-axis "Time (nanoseconds)" 0 --> 6
    BAR [4.366, 4.755, 1.207]

Cached Access Performance

xychart-beta
    title "Cached Access Performance"
    x-axis "Implementation" ["LazyLock", "OnceLock", "QuickBool"]
    y-axis "Time (nanoseconds)" 0 --> 1
    BAR [0.291, 0.438, 0.275]

Usage

Add quick-bool to your Cargo.toml:

[dependencies]
quick-bool = "0.1.0"

Basic Usage

use quick_bool::QuickBool;

let quick_bool = QuickBool::new();

// First access computes the value
let value = quick_bool.get_or_set(|| {
    // Expensive computation here
    std::thread::sleep(std::time::Duration::from_millis(100));
    true
});

// Subsequent access returns the cached value immediately
let cached_value = quick_bool.get_or_set(|| panic!("This won't execute"));
assert_eq!(value, cached_value);

Checking State

use quick_bool::QuickBool;

let qb = QuickBool::new();

// Check if value has been computed
assert!(!qb.is_set());

// Get current value without computing
assert_eq!(qb.get(), None);

// Compute the value
qb.get_or_set(|| false);

// Now it's set
assert!(qb.is_set());
assert_eq!(qb.get(), Some(false));

Resetting

use quick_bool::QuickBool;

let qb = QuickBool::new();
qb.get_or_set(|| true);
assert!(qb.is_set());

// Reset to allow recomputation
qb.reset();
assert!(!qb.is_set());

// Can compute again
let new_value = qb.get_or_set(|| false);
assert_eq!(new_value, false);

Thread-Safe Usage

use quick_bool::QuickBool;
use std::sync::Arc;
use std::thread;

let qb = Arc::new(QuickBool::new());
let mut handles = vec![];

// Spawn multiple threads
for _ in 0..4 {
    let qb_clone = Arc::clone(&qb);
    let handle = thread::spawn(move || {
        qb_clone.get_or_set(|| {
            // This expensive computation only happens once
            // across all threads
            std::thread::sleep(std::time::Duration::from_millis(50));
            true
        })
    });
    handles.push(handle);
}

// Wait for all threads
let results: Vec<bool> = handles.into_iter()
    .map(|h| h.join().unwrap())
    .collect();

// All threads get the same result
assert!(results.iter().all(|&x| x));

Performance-Optimized Usage

For maximum performance when you know the value is cached:

use quick_bool::QuickBool;

let qb = QuickBool::new();
qb.get_or_set(|| expensive_computation());

// Fast cached access when you know it's set
if let Some(value) = qb.get() {
    // Fast cached access (270 ps)
    println!("Value: {}", value);
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Use Cases

  • Configuration flags that are expensive to compute
  • Feature flags with complex evaluation logic
  • Caching computed boolean results
  • Any scenario where you need a thread-safe, lazy boolean with frequent reads