neobit
Zero-dependency, lightweight bitflags with readable debug output.
Features
- Zero dependencies - Pure Rust, no external crates
- Readable debug output -
Flags(READ | WRITE)instead ofFlags { bits: 3 } const fnoperations - Use in const contexts withunion(),intersection(), etc.no_stdcompatible - Works in embedded environments- All integer types - Supports
u8-u128andi8-i128 - Built-in
all()method - Get all flags without manual constants - Flexible bit validation - Both
from_bits()(validated) andfrom_bits_retain()(unchecked)
Quick Start
use neobit;
neobit!
The all() Method
neobit provides a built-in all() method that returns the union of all defined flags:
neobit!
// No need for manual ALL constants!
let all = all; // Contains A | B | C
// Works in const context too
const ALL_FLAGS: Flags = all;
Benefits:
- Less boilerplate - No need to manually define ALL constants
- Always in sync - Automatically includes all flags, even when new ones are added
- Const-compatible - Can be used in compile-time expressions
Limitations
Composite Constants in Macro
Composite constants can be defined in the macro, but require using .union().bits() syntax:
neobit!
Alternatively, define composite constants outside the macro for cleaner syntax:
The .bits() requirement in the macro is due to how Rust evaluates const expressions in macro contexts.
Who Should Use This
Good Fit
- C FFI bindings (hardware registers, system calls)
- Protocol parsing (network packets, binary formats)
- Embedded systems (
no_stdenvironments) - Libraries that want minimal dependencies
Consider bitflags Instead
- You need iterator support
- You're building a beginner-friendly application
- You prefer always-valid flags by default
Design Philosophy
Flexible Bit Validation
neobit provides both validated and unchecked bit operations:
// Safe validation - returns None for unknown bits
let flags = from_bits; // Some(Permissions)
let invalid = from_bits; // None
// Unchecked retention - preserves all bits
let flags = from_bits_retain; // All bits kept
This represents different design choices:
| Aspect | neobit | bitflags |
|---|---|---|
| Default construction | From<T> uses from_bits_retain() (unchecked) |
Requires explicit construction |
| Unknown bits handling | Preserved by default | Validated by default |
| Validation available | ✅ from_bits() returns Option<Self> |
✅ Built-in validation |
| Best for | FFI, protocols, hardware registers | Application-level flags |
API Overview
Operators
| Operator | Meaning | const fn equivalent |
|---|---|---|
| |
Union | union() |
& |
Intersection | intersection() |
^ |
Symmetric difference | symmetric_difference() |
! |
Complement | complement() |
- |
Difference | difference() |
All operators have *Assign variants (|=, &=, etc.).
Methods
// Construction
empty
all // All defined flags
from_bits // Validated, returns Option<Self>
from_bits_retain // Unchecked, preserves all bits
// Access
flags.bits
flags.is_empty
flags.contains
flags.intersects
// Mutation
flags.insert
flags.remove
flags.toggle
// Const operations
flags.union
flags.intersection
flags.difference
flags.symmetric_difference
flags.complement
Const Context
Use const methods for compile-time flag combinations:
neobit!
const MASK: Flags = A.union; // Compile-time
const ALL_FLAGS: Flags = all; // All flags in const context
Type Conversion
// From/Into
let flags: Flags = 0b11.into;
let bits: u8 = flags.into;
// Explicit
let flags = from_bits_retain;
let validated = from_bits;
let bits = flags.bits;
Complement Operation Difference
neobit and bitflags implement complement() (or ! operator) differently:
neobit!
let flags = A; // 0b01
// neobit: Pure bitwise complement
let neobit_comp = flags.complement; // !0b01 = 0b11111110
// bitflags: Complement of defined flags only
// let bitflags_comp = !flags; // !0b01 & 0b11 = 0b10
Why this matters:
- neobit preserves all bit information - essential for hardware registers and protocols
- bitflags masks to defined flags - safer for application-level code
Signed Types Warning
Signed integers are supported for C FFI compatibility, but be careful with ! (complement):
neobit!
let complement = !A;
// i8: !0b0001 = -2 (two's complement)
// u8: !0b0001 = 254
// Prefer difference() for removing flags:
let all = all;
let without_a = all.difference;
Debug Output
Single-bit flags are shown by name. Composite constants are expanded:
println!; // Flags(READ)
println!; // Flags(READ | WRITE)
println!; // Flags(READ | WRITE | EXECUTE)
println!; // Flags(empty)
println!; // Flags(0x80)
Minimum Rust Version
neobit requires Rust 1.56 or later.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.