Address Ranges

Relevant source files

This document covers the address range functionality provided by the memory_addr crate, specifically the AddrRange generic type and its associated operations. Address ranges represent contiguous spans of memory addresses with type safety and comprehensive range manipulation operations.

For information about individual address types and arithmetic operations, see Address Types and Operations. For page iteration over ranges, see Page Iteration.

Address Range Structure

The core of the address range system is the AddrRange<A> generic struct, where A implements the MemoryAddr trait. This provides type-safe representation of memory address ranges with inclusive start bounds and exclusive end bounds.

AddrRange Type Hierarchy

flowchart TD
subgraph subGraph2["Address Types"]
    VA["VirtAddr"]
    PA["PhysAddr"]
    UA["usize"]
end
subgraph subGraph1["Concrete Type Aliases"]
    VAR["VirtAddrRangeAddrRange<VirtAddr>"]
    PAR["PhysAddrRangeAddrRange<PhysAddr>"]
end
subgraph subGraph0["Generic Types"]
    AR["AddrRange<A>Generic range type"]
    MA["MemoryAddr traitConstraint for A"]
end

AR --> MA
AR --> UA
PA --> MA
PAR --> AR
PAR --> PA
UA --> MA
VA --> MA
VAR --> AR
VAR --> VA

Sources: memory_addr/src/range.rs(L1 - L28)  memory_addr/src/range.rs(L365 - L368) 

The AddrRange<A> struct contains two public fields:

  • start: A - The lower bound of the range (inclusive)
  • end: A - The upper bound of the range (exclusive)

Type aliases provide convenient names for common address range types:

  • VirtAddrRange = AddrRange<VirtAddr>
  • PhysAddrRange = AddrRange<PhysAddr>

Range Construction Methods

Address ranges can be constructed through several methods, each with different safety and error-handling characteristics.

Construction Method Categories

MethodSafetyOverflow HandlingUse Case
new()Panics on invalid rangeCheckedSafe construction with panic
try_new()ReturnsOptionCheckedFallible construction
new_unchecked()UnsafeUncheckedPerformance-critical paths
from_start_size()Panics on overflowCheckedSize-based construction
try_from_start_size()ReturnsOptionCheckedFallible size-based construction
from_start_size_unchecked()UnsafeUncheckedPerformance-critical size-based

Sources: memory_addr/src/range.rs(L34 - L193) 

Range Construction Flow

flowchart TD
subgraph Results["Results"]
    SUCCESS["AddrRange<A>"]
    PANIC["Panic"]
    NONE["None"]
    ERROR["Error"]
end
subgraph Validation["Validation"]
    CHECK["start <= end?"]
    OVERFLOW["Addition overflow?"]
end
subgraph subGraph1["Construction Methods"]
    NEW["new()"]
    TRYNEW["try_new()"]
    UNSAFE["new_unchecked()"]
    FSS["from_start_size()"]
    TRYFSS["try_from_start_size()"]
    UNSAFEFSS["from_start_size_unchecked()"]
    TRYFROM["TryFrom<Range<T>>"]
end
subgraph subGraph0["Input Types"]
    SE["start, end addresses"]
    SS["start address, size"]
    RNG["Rust Range<T>"]
end
START["Range Construction Request"]

CHECK --> NONE
CHECK --> PANIC
CHECK --> SUCCESS
FSS --> OVERFLOW
NEW --> CHECK
OVERFLOW --> NONE
OVERFLOW --> PANIC
OVERFLOW --> SUCCESS
RNG --> TRYFROM
SE --> NEW
SE --> TRYNEW
SE --> UNSAFE
SS --> FSS
SS --> TRYFSS
SS --> UNSAFEFSS
START --> RNG
START --> SE
START --> SS
TRYFROM --> CHECK
TRYFSS --> OVERFLOW
TRYNEW --> CHECK
UNSAFE --> SUCCESS
UNSAFEFSS --> SUCCESS

Sources: memory_addr/src/range.rs(L57 - L193)  memory_addr/src/range.rs(L307 - L317) 

Range Operations and Relationships

Address ranges support comprehensive operations for checking containment, overlap, and spatial relationships between ranges.

Range Relationship Operations

flowchart TD
subgraph Results["Results"]
    BOOL["bool"]
    USIZE["usize"]
end
subgraph subGraph1["Query Operations"]
    CONTAINS["contains(addr: A)Point containment"]
    CONTAINSRANGE["contains_range(other)Range containment"]
    CONTAINEDIN["contained_in(other)Reverse containment"]
    OVERLAPS["overlaps(other)Range intersection"]
    ISEMPTY["is_empty()Zero-size check"]
    SIZE["size()Range size"]
end
subgraph subGraph0["Range A"]
    RA["AddrRange<A>"]
end

CONTAINEDIN --> BOOL
CONTAINS --> BOOL
CONTAINSRANGE --> BOOL
ISEMPTY --> BOOL
OVERLAPS --> BOOL
RA --> CONTAINEDIN
RA --> CONTAINS
RA --> CONTAINSRANGE
RA --> ISEMPTY
RA --> OVERLAPS
RA --> SIZE
SIZE --> USIZE

Sources: memory_addr/src/range.rs(L228 - L302) 

Key Range Operations

The following operations are available on all AddrRange<A> instances:

  • Point Containment: contains(addr) checks if a single address falls within the range
  • Range Containment: contains_range(other) checks if another range is entirely within this range
  • Containment Check: contained_in(other) checks if this range is entirely within another range
  • Overlap Detection: overlaps(other) checks if two ranges have any intersection
  • Empty Range Check: is_empty() returns true if start equals end
  • Size Calculation: size() returns the number of bytes in the range

Convenience Macros

The crate provides three macros for convenient address range creation with compile-time type inference and runtime validation.

Macro Overview

MacroTarget TypePurpose
addr_range!AddrRange(inferred)Generic range creation
va_range!VirtAddrRangeVirtual address range creation
pa_range!PhysAddrRangePhysical address range creation

Sources: memory_addr/src/range.rs(L391 - L448) 

Macro Usage Pattern

flowchart TD
subgraph subGraph3["Output Types"]
    GENERICRANGE["AddrRange<A> (inferred)"]
    VIRTRANGE["VirtAddrRange"]
    PHYSRANGE["PhysAddrRange"]
end
subgraph subGraph2["Internal Processing"]
    TRYFROM["TryFrom<Range<T>>::try_from()"]
    EXPECT["expect() on Result"]
end
subgraph subGraph1["Macro Processing"]
    ADDRRANGE["addr_range!(0x1000..0x2000)"]
    VARANGE["va_range!(0x1000..0x2000)"]
    PARANGE["pa_range!(0x1000..0x2000)"]
end
subgraph subGraph0["Input Syntax"]
    RANGE["Rust range syntaxstart..end"]
end

ADDRRANGE --> TRYFROM
EXPECT --> GENERICRANGE
EXPECT --> PHYSRANGE
EXPECT --> VIRTRANGE
PARANGE --> TRYFROM
RANGE --> ADDRRANGE
RANGE --> PARANGE
RANGE --> VARANGE
TRYFROM --> EXPECT
VARANGE --> TRYFROM

Sources: memory_addr/src/range.rs(L391 - L448) 

Usage Examples and Patterns

The test suite demonstrates common usage patterns for address ranges, showing both basic operations and complex relationship checking.

Basic Range Operations

// Creating ranges with different methods
let range = VirtAddrRange::new(0x1000.into(), 0x2000.into());
let size_range = VirtAddrRange::from_start_size(0x1000.into(), 0x1000);

// Using macros for convenience
let macro_range = va_range!(0x1000..0x2000);

// Checking basic properties
assert_eq!(range.size(), 0x1000);
assert!(!range.is_empty());
assert!(range.contains(0x1500.into()));

Sources: memory_addr/src/range.rs(L464 - L511) 

Range Relationship Testing

The codebase extensively tests range relationships using various scenarios:

// Containment checking
assert!(range.contains_range(va_range!(0x1001..0x1fff)));
assert!(!range.contains_range(va_range!(0xfff..0x2001)));

// Overlap detection
assert!(range.overlaps(va_range!(0x1800..0x2001)));
assert!(!range.overlaps(va_range!(0x2000..0x2800)));

// Spatial relationships
assert!(range.contained_in(va_range!(0xfff..0x2001)));

Sources: memory_addr/src/range.rs(L483 - L505) 

Error Handling Patterns

The range system provides both panicking and fallible construction methods:

// Panicking construction (for known-valid ranges)
let valid_range = VirtAddrRange::new(start, end);

// Fallible construction (for potentially invalid input)
if let Some(range) = VirtAddrRange::try_new(start, end) {
    // Use the valid range
}

// Size-based construction with overflow handling
let safe_range = VirtAddrRange::try_from_start_size(start, size)?;

Sources: memory_addr/src/range.rs(L58 - L167)