pub trait BoundTypeChecks {
// Required method
fn includes_boundary(&self) -> bool;
// Provided methods
fn is_open(&self) -> bool { ... }
fn is_closed(&self) -> bool { ... }
}Expand description
Runtime queries for boundary inclusion semantics (open vs closed bounds).
BoundTypeChecks provides a unified interface for determining whether a bound includes
or excludes its boundary value at runtime. This trait enables generic programming over
different boundary inclusion semantics while maintaining mathematical correctness and type safety.
§Design Philosophy
§Runtime Type Detection
Unlike the compile-time BoundType trait that provides static type information,
BoundTypeChecks operates on bound instances to determine their inclusion semantics:
use grid1d::bounds::*;
use try_create::New;
fn analyze_bound_inclusion<B: BoundTypeChecks>(bound: &B) -> String {
if bound.is_closed() {
"This bound includes its boundary value".to_string()
} else {
"This bound excludes its boundary value".to_string()
}
}
let closed = LowerBoundClosed::new(0.0);
let open = UpperBoundOpen::new(10.0);
assert_eq!(analyze_bound_inclusion(&closed), "This bound includes its boundary value");
assert_eq!(analyze_bound_inclusion(&open), "This bound excludes its boundary value");§Complement Relationship
The two derived methods in this trait are logical complements:
is_closed() == includes_boundary()
is_open() == !includes_boundary()This relationship is enforced by the default implementations of BoundTypeChecks::is_closed() and BoundTypeChecks::is_open(),
ensuring mathematical consistency across all implementations.
§Mathematical Semantics
§Closed Bounds (Inclusive)
Closed bounds include their boundary values in the constraint:
| Bound Type | Mathematical Constraint | Notation | Meaning |
|---|---|---|---|
LowerBoundClosed | x ≥ bound_value | [a | Includes minimum |
UpperBoundClosed | x ≤ bound_value | b] | Includes maximum |
§Open Bounds (Exclusive)
Open bounds exclude their boundary values from the constraint:
| Bound Type | Mathematical Constraint | Notation | Meaning |
|---|---|---|---|
LowerBoundOpen | x > bound_value | (a | Excludes minimum |
UpperBoundOpen | x < bound_value | b) | Excludes maximum |
§Core Methods
§BoundTypeChecks::includes_boundary()
The fundamental method that determines whether the boundary value is part of the constraint. This is the only method implementors must provide:
use grid1d::bounds::*;
use try_create::New;
let closed_lower = LowerBoundClosed::new(5.0);
let open_lower = LowerBoundOpen::new(5.0);
let closed_upper = UpperBoundClosed::new(10.0);
let open_upper = UpperBoundOpen::new(10.0);
// Closed bounds include their boundary
assert!(closed_lower.includes_boundary());
assert!(closed_upper.includes_boundary());
// Open bounds exclude their boundary
assert!(!open_lower.includes_boundary());
assert!(!open_upper.includes_boundary());§BoundTypeChecks::is_closed()
Returns true if this bound includes its boundary value. This is a convenience method
that delegates to BoundTypeChecks::includes_boundary():
use grid1d::bounds::*;
use try_create::New;
assert!(LowerBoundClosed::new(0.0).is_closed());
assert!(!LowerBoundClosed::new(1.0).is_open());
assert!(UpperBoundClosed::new(2.0).is_closed());
assert!(!UpperBoundClosed::new(3.0).is_open());
assert!(!LowerBoundOpen::new(4.0).is_closed());
assert!(LowerBoundOpen::new(5.0).is_open());
assert!(!UpperBoundOpen::new(6.0).is_closed());
assert!(UpperBoundOpen::new(7.0).is_open());§BoundTypeChecks::is_open()
Returns true if this bound excludes its boundary value. This is implemented as
the logical negation of BoundTypeChecks::includes_boundary():
use grid1d::bounds::*;
use try_create::New;
let open_lower = LowerBoundOpen::new(1.0);
let open_upper = UpperBoundOpen::new(2.0);
let closed_lower = LowerBoundClosed::new(1.0);
let closed_upper = UpperBoundClosed::new(2.0);
// Open bounds return true
assert!(open_lower.is_open());
assert!(open_upper.is_open());
assert!(!open_lower.is_closed());
assert!(!open_upper.is_closed());
// Closed bounds return false
assert!(!closed_lower.is_open());
assert!(!closed_upper.is_open());
assert!(closed_lower.is_closed());
assert!(closed_upper.is_closed());§Generic Programming Applications
§Constraint Analysis
use grid1d::bounds::*;
use try_create::New;
fn analyze_constraint_strictness<B: BoundTypeChecks + AsRef<f64>>(bounds: &[B]) -> (usize, usize) {
let (strict, inclusive): (Vec<_>, Vec<_>) = bounds.iter()
.partition(|bound| bound.is_open());
(strict.len(), inclusive.len())
}
let mixed_lower_bounds: Vec<LowerBoundRuntime<f64>> = vec![
LowerBoundClosed::new(0.0).into(), // Inclusive
LowerBoundOpen::new(1.0).into(), // Strict
];
let mixed_upper_bounds: Vec<UpperBoundRuntime<f64>> = vec![
UpperBoundClosed::new(10.0).into(), // Inclusive
UpperBoundOpen::new(9.0).into(), // Strict
UpperBoundOpen::new(8.0).into(), // Strict
];
let (strict_count, inclusive_count) = analyze_constraint_strictness(&mixed_lower_bounds);
assert_eq!(strict_count, 1); // One open bounds
assert_eq!(inclusive_count, 1); // One closed bounds
let (strict_count, inclusive_count) = analyze_constraint_strictness(&mixed_upper_bounds);
assert_eq!(strict_count, 2); // Two open bounds
assert_eq!(inclusive_count, 1); // One closed bounds§Boundary Behavior Validation
use grid1d::bounds::*;
use try_create::New;
fn validate_boundary_consistency<B>(bound: &B, test_value: f64) -> bool
where
B: BoundTypeChecks + ValueWithinBound<RealType = f64> + AsRef<f64>,
{
let boundary_value = *bound.as_ref();
let at_boundary = (test_value - boundary_value).abs() < f64::EPSILON;
if at_boundary {
// At the boundary, constraint should match inclusion semantics
bound.value_within_bound(&test_value) == bound.includes_boundary()
} else {
// Away from boundary, inclusion type shouldn't matter for this test
true
}
}
let closed_bound = LowerBoundClosed::new(5.0);
let open_bound = LowerBoundOpen::new(5.0);
// Test boundary value behavior
assert!(validate_boundary_consistency(&closed_bound, 5.0)); // Should include 5.0
assert!(validate_boundary_consistency(&open_bound, 5.0)); // Should exclude 5.0
// Test non-boundary values
assert!(validate_boundary_consistency(&closed_bound, 6.0)); // Both should include 6.0
assert!(validate_boundary_consistency(&open_bound, 6.0));§Dynamic Interval Construction
use grid1d::bounds::*;
use try_create::New;
fn describe_interval_boundary<L, U>(lower: &L, upper: &U) -> String
where
L: BoundTypeChecks + AsRef<f64>,
U: BoundTypeChecks + AsRef<f64>,
{
let left_bracket = if lower.is_closed() { "[" } else { "(" };
let right_bracket = if upper.is_closed() { "]" } else { ")" };
format!("{}{}, {}{}",
left_bracket, lower.as_ref(),
upper.as_ref(), right_bracket)
}
let bounds_combinations: Vec<(LowerBoundRuntime<f64>, UpperBoundRuntime<f64>)> = vec![
(LowerBoundClosed::new(0.0).into(), UpperBoundClosed::new(1.0).into()), // [0, 1]
(LowerBoundOpen::new(0.0).into(), UpperBoundOpen::new(1.0).into()), // (0, 1)
(LowerBoundClosed::new(0.0).into(), UpperBoundOpen::new(1.0).into()), // [0, 1)
(LowerBoundOpen::new(0.0).into(), UpperBoundClosed::new(1.0).into()), // (0, 1]
];
let descriptions: Vec<String> = bounds_combinations.iter()
.map(|(l, u)| describe_interval_boundary(l, u))
.collect();
assert_eq!(descriptions, vec!["[0, 1]", "(0, 1)", "[0, 1)", "(0, 1]"]);§Integration with Runtime Bounds
The trait works seamlessly with runtime bound types:
use grid1d::bounds::*;
use try_create::New;
fn analyze_runtime_bound_types(
lower: &LowerBoundRuntime<f64>,
upper: &UpperBoundRuntime<f64>
) -> String {
let lower_type = if lower.is_closed() { "closed" } else { "open" };
let upper_type = if upper.is_closed() { "closed" } else { "open" };
format!("Lower: {} ({}), Upper: {} ({})",
lower.as_ref(), lower_type,
upper.as_ref(), upper_type)
}
let lower = IntervalBoundRuntime::Closed(LowerBoundClosed::new(0.0));
let upper = IntervalBoundRuntime::Open(UpperBoundOpen::new(1.0));
assert_eq!(
analyze_runtime_bound_types(&lower, &upper),
"Lower: 0 (closed), Upper: 1 (open)"
);§Mathematical Invariant Verification
The trait enables runtime validation of mathematical properties:
use grid1d::bounds::*;
use try_create::New;
fn verify_inclusion_consistency<B: BoundTypeChecks>(bound: &B) -> bool {
// Verify the complement relationship holds
bound.is_closed() == bound.includes_boundary() &&
bound.is_open() == !bound.includes_boundary()
}
fn verify_boundary_semantics<B>(bound: &B, boundary_value: f64) -> Result<(), String>
where
B: BoundTypeChecks + ValueWithinBound<RealType = f64> + AsRef<f64>,
{
if !verify_inclusion_consistency(bound) {
return Err("Bound inclusion consistency check failed".to_string());
}
// The boundary value itself should only satisfy the constraint if the bound is closed
let boundary_satisfies = bound.value_within_bound(&boundary_value);
if boundary_satisfies != bound.includes_boundary() {
return Err("Boundary constraint behavior inconsistent with inclusion type".to_string());
}
Ok(())
}
let closed_bound = LowerBoundClosed::new(5.0);
let open_bound = LowerBoundOpen::new(5.0);
assert!(verify_boundary_semantics(&closed_bound, 5.0).is_ok());
assert!(verify_boundary_semantics(&open_bound, 5.0).is_ok());§Performance Characteristics
§Runtime Complexity
includes_boundary(): O(1) - typically compiles to a constant or simple type checkis_closed(): O(1) - delegates toincludes_boundary()is_open(): O(1) - logical negation ofincludes_boundary()- Memory: No additional storage overhead beyond the underlying bound
§Optimization Notes
- All methods are marked
#[inline(always)]for zero-cost abstractions - The complement relationship enables compiler optimizations
- For compile-time bounds, inclusion information is known statically and optimized away
- Runtime bounds have small pattern matching overhead but maintain correctness
§Implementation Requirements
Implementors must provide:
includes_boundary(): Core method that determines boundary inclusion semantics- Consistency: The method must return consistent results for the lifetime of the object
- Mathematical Correctness: Return
truefor closed bounds,falsefor open bounds
§Example Implementation
use grid1d::bounds::*;
struct CustomBound {
value: f64,
is_inclusive: bool,
}
impl BoundTypeChecks for CustomBound {
fn includes_boundary(&self) -> bool {
self.is_inclusive
}
}
let inclusive = CustomBound { value: 5.0, is_inclusive: true };
let exclusive = CustomBound { value: 5.0, is_inclusive: false };
assert!(inclusive.is_closed());
assert!(!inclusive.is_open());
assert!(inclusive.includes_boundary());
assert!(!exclusive.is_closed());
assert!(exclusive.is_open());
assert!(!exclusive.includes_boundary());§Mathematical Guarantees
The BoundTypeChecks trait maintains mathematical correctness by:
- Complement Relationship: Ensuring exactly one of
is_open()oris_closed()is true - Consistency: Boundary inclusion semantics remain constant for the object’s lifetime
- Type Safety: Preventing confusion between inclusive and exclusive constraints
- Constraint Semantics: Properly reflecting the mathematical meaning of open vs closed bounds
Use BoundTypeChecks when you need to determine boundary inclusion behavior at runtime
while maintaining mathematical correctness and type safety. For compile-time inclusion
information, prefer the static BoundType trait and its associated types (Open, Closed).
Required Methods§
Sourcefn includes_boundary(&self) -> bool
fn includes_boundary(&self) -> bool
Returns whether the boundary value is included in the interval