ranges-ext
An efficient range/interval set data structure designed for no_std environments, with support for metadata, smart merging, and interval splitting.
Core Features
- Trait-based Design - Support custom interval types via
RangeInfotrait - Smart Merging - Automatically merge overlapping or adjacent intervals with the same kind
- Metadata Support - Each interval can carry custom metadata (kind)
- Overwrite Control - Precise control over which intervals can be overwritten
- Dual Mode Support - heapless mode (stack-allocated) and alloc mode (heap-allocated)
- Interval Splitting - Remove operations can automatically split existing intervals
- Zero-copy Iteration - Efficient interval traversal
no_stdCompatible - Suitable for embedded and bare-metal environments
Installation
Basic Installation (heapless mode)
[]
= "0.5"
Enable Alloc Feature (optional)
[]
= { = "0.5", = ["alloc"] }
This library is #![no_std] by default and can be used directly in embedded environments. Enable the alloc feature to use dynamic capacity mode in standard environments.
Quick Start
Heapless Mode (suitable for no_std environments)
use ;
use Range;
Alloc Mode (suitable for standard environments)
use ;
// [Same MyRange definition as above]
Simple Intervals Without Metadata
If you don't need metadata, you can use the unit type ():
use ;
let mut temp_buffer = ;
let mut set: Vec = new;
set.merge_add?;
Core Concepts
RangeInfo Trait
RangeInfo is the core trait that defines the requirements for interval types:
Important Change (0.5.0): The kind() method now returns the owned type Self::Kind instead of a reference &Self::Kind.
Two Operation Modes
RangeVecOps (Heapless Mode)
Provides interval operations for fixed-capacity vectors (like heapless::Vec<T, N>):
- Requires temporary buffer: All methods need a
&mut [u8]for temporary storage - Use cases: no_std environments, embedded systems, deterministic memory usage
;
;
RangeVecAllocOps (Alloc Mode)
Provides interval operations for dynamic vectors (alloc::vec::Vec<T>):
- No temporary buffer needed: Internally manages temporary storage
- Use cases: Standard environments, dynamic capacity needed
;
;
Kind System
Kind is metadata for each interval, used to:
- Control merging behavior: Only adjacent intervals with the same kind will merge
- Distinguish interval types: e.g., "read-only", "read-write", "reserved"
- Implement business logic: e.g., different memory region types, permission levels
Example:
// Same kind, will merge
set.merge_add?;
set.merge_add?;
// Result: [0, 20) kind="A"
// Different kinds, won't merge
set.merge_add?;
set.merge_add?;
// Result: [0, 10) kind="A", [10, 20) kind="B"
Temporary Buffer Explanation
In heapless mode, merge_add and merge_remove operations require a temporary buffer.
Why is it needed?
- Interval splitting and merging need temporary storage for intermediate results
- heapless::Vec cannot dynamically expand during operations
- Using byte buffers avoids additional generic parameters
How to calculate size?
// Temporary buffer size = element size × expected max number of elements
let elem_size = ;
let max_elements = 128; // Adjust based on actual needs
let mut temp_buffer = ;
// More conservative calculation (considering alignment and splitting operations)
let mut temp_buffer = ;
Best practices:
- Reserve sufficient space: At least enough to store all current elements
- Reusable: The same buffer can be used for multiple operations
- Can be static: Suitable for global singleton scenarios
Usage Guide
Interval Overwrite Control
let mut set: Vec = new;
let mut temp = ;
// Add a non-overwritable interval
set.merge_add?;
// Attempting to add a conflicting interval will fail
let result = set.merge_add;
assert!;
// Overwritable intervals can be replaced
set.merge_add?;
set.merge_add?;
// [5, 15) is partially overlapped and merged by [10, 25)
Interval Splitting
let mut set: Vec = new;
let mut temp = ;
set.merge_add?;
// Current: [10, 40) kind="A"
// Remove middle part
set.merge_remove?;
// Result: [10, 20) kind="A", [30, 40) kind="A"
assert_eq!;
Batch Operations
let ranges = vec!;
// heapless mode
set.merge_extend?;
// alloc mode
set.merge_extend?;
Error Handling
Example:
match set.merge_add
Example Code
The project includes the following examples (located in the examples/ directory):
debug_demo.rs - Basic Debugging
Demonstrates basic interval merging and iteration.
Run:
key_demo.rs - Kind Demonstration
Shows how intervals with different kinds interact.
Run:
overlap_demo.rs - Overwrite and Splitting
Demonstrates various scenarios of interval overwriting and splitting.
Run:
slicevec_demo.rs - Temporary Buffer
Shows how to use temporary buffers.
Run:
Mode Selection
Heapless Mode
Pros:
- Stack-allocated, no heap fragmentation
- Predictable memory usage
- Suitable for no_std environments
- Compile-time determined capacity
Cons:
- Requires temporary buffer
- Fixed capacity, may overflow
- Manual buffer size management needed
Use cases:
- Embedded systems
- Bare-metal programs
- Deterministic memory management required
- Predictable number of intervals
Alloc Mode
Pros:
- No temporary buffer needed
- Dynamic capacity, won't overflow
- Simpler API
Cons:
- Requires heap allocator
- Potential memory fragmentation
- Not suitable for strict no_std environments
Use cases:
- Standard environments
- Unpredictable number of intervals
- Development convenience prioritized
Performance and Limitations
Time Complexity
- Add interval (
merge_add): O(n) - needs to traverse existing intervals - Remove interval (
merge_remove): O(n) - needs to traverse and split - Query contains (
contains_point): O(log n) - uses binary search - Iteration (
iter): O(n) - zero-copy, just iteration
Space Complexity
- heapless mode: O(N) - N is compile-time specified capacity
- alloc mode: O(n) - n is actual number of stored intervals
- Temporary buffer: O(n) - additional space needed for heapless mode
Limitations
-
Capacity limitation (heapless mode)
- Exceeding capacity returns
RangeError::Capacity - Need to estimate maximum number of intervals
- Exceeding capacity returns
-
Type requirements
RangeInfo::Typemust implementOrd + CopyRangeInfo::Kindmust implementDebug + Eq + Clone
-
Interval semantics
- Uses half-open intervals
[start, end) - Intervals with
start >= endare ignored
- Uses half-open intervals
FAQ
Q: How to calculate the temporary buffer size?
A: Buffer size depends on interval type size and expected maximum number of elements:
let elem_size = ;
let max_elements = 128; // Expected max number of intervals
let mut temp_buffer = ;
// More conservative calculation (considering alignment and split operations)
let mut temp_buffer = ;
Q: Why do only intervals with the same kind merge?
A: This design supports finer-grained interval management:
// Scenario: memory region management
// May need to distinguish "read-only", "read-write", "reserved" regions
// Even if adjacent, they should not merge
set.merge_add?;
set.merge_add?;
// Result keeps two separate intervals
Q: How to use in strict no_std environments?
A: Use heapless mode with stack-allocated buffer:
Q: What should I pay attention to when upgrading from 0.2.x to 0.5.0?
A: Major changes:
-
RangeInfo::kind() return type changed
// Old version ; // New version (0.5.0) ; -
RangeSet struct no longer provided
- Directly use
heapless::Vec<T, N>oralloc::vec::Vec<T> - Gain interval operations through
RangeVecOpsorRangeVecAllocOpstraits
- Directly use
-
API renamed
add()→merge_add()remove()→merge_remove()extend()→merge_extend()contains()→contains_point()
Q: How to handle interval conflicts?
A: Use the overwritable field to control:
// Protect critical intervals
set.merge_add?;
// Attempting to overwrite will fail
match set.merge_add
Changelog
See CHANGELOG.md for version history and changes.
License
Dual licensed under MIT or Apache-2.0, you may choose either.