Expand description
§Tester Type
Provides tester implementations that test conditions or states and return boolean values, without accepting input parameters.
§Overview
Tester is a functional abstraction for testing conditions or states without accepting input. It can check system status, wait for conditions, or perform health checks.
This module implements Option 3 from the design document: a unified
Tester trait with multiple concrete implementations optimized for
different ownership and concurrency scenarios.
§Core Design Principles
- Returns boolean:
Testerreturnsboolto indicate test results - Uses
&self: Tester is only responsible for “judgment”, not “state management” - No TesterOnce: Very limited use cases, lacks practical examples
- State management is caller’s responsibility: Tester only reads state, does not modify state
§Three Implementations
-
BoxTester: Single ownership usingBox<dyn Fn() -> bool>. Zero overhead, cannot be cloned. Best for one-time use and builder patterns. -
ArcTester: Thread-safe shared ownership usingArc<dyn Fn() -> bool + Send + Sync>. Can be cloned and sent across threads. Lock-free overhead. -
RcTester: Single-threaded shared ownership usingRc<dyn Fn() -> bool>. Can be cloned but cannot be sent across threads. Lower overhead thanArcTester.
§Comparison with Other Functional Abstractions
| Type | Input | Output | self | Modify? | Use Cases |
|---|---|---|---|---|---|
| Tester | None | bool | &self | No | State Check |
| Predicate | &T | bool | &self | No | Filter |
| Supplier | None | T | &mut | Yes | Factory |
§Examples
§Basic State Checking
use prism3_function::{BoxTester, Tester};
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
// State managed externally
let count = Arc::new(AtomicUsize::new(0));
let count_clone = Arc::clone(&count);
let tester = BoxTester::new(move || {
count_clone.load(Ordering::Relaxed) <= 3
});
assert!(tester.test()); // true (0)
count.fetch_add(1, Ordering::Relaxed);
assert!(tester.test()); // true (1)
count.fetch_add(1, Ordering::Relaxed);
assert!(tester.test()); // true (2)
count.fetch_add(1, Ordering::Relaxed);
assert!(tester.test()); // true (3)
count.fetch_add(1, Ordering::Relaxed);
assert!(!tester.test()); // false (4)§Logical Combination
use prism3_function::{BoxTester, Tester};
use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
// Simulate microservice health check scenario
let cpu_usage = Arc::new(AtomicUsize::new(0));
let memory_usage = Arc::new(AtomicUsize::new(0));
let is_healthy = Arc::new(AtomicBool::new(true));
let is_ready = Arc::new(AtomicBool::new(false));
let max_cpu = 80;
let max_memory = 90;
let cpu_clone = Arc::clone(&cpu_usage);
let memory_clone = Arc::clone(&memory_usage);
let health_clone = Arc::clone(&is_healthy);
let ready_clone = Arc::clone(&is_ready);
// System resource check: CPU and memory within safe limits
let resources_ok = BoxTester::new(move || {
cpu_clone.load(Ordering::Relaxed) < max_cpu
})
.and(move || {
memory_clone.load(Ordering::Relaxed) < max_memory
});
// Service status check: healthy or ready
let service_ok = BoxTester::new(move || {
health_clone.load(Ordering::Relaxed)
})
.or(move || {
ready_clone.load(Ordering::Relaxed)
});
// Combined condition: resources normal and service available
let can_accept_traffic = resources_ok.and(service_ok);
// Test different state combinations
// Initial state: resources normal and service healthy
cpu_usage.store(50, Ordering::Relaxed);
memory_usage.store(60, Ordering::Relaxed);
assert!(can_accept_traffic.test()); // resources normal and service healthy
// Service unhealthy but ready
is_healthy.store(false, Ordering::Relaxed);
is_ready.store(true, Ordering::Relaxed);
assert!(can_accept_traffic.test()); // resources normal and service ready
// CPU usage too high
cpu_usage.store(95, Ordering::Relaxed);
assert!(!can_accept_traffic.test()); // resources exceeded
// Service unhealthy but ready
is_healthy.store(false, Ordering::Relaxed);
cpu_usage.store(50, Ordering::Relaxed);
assert!(can_accept_traffic.test()); // still ready§Thread-Safe Sharing
use prism3_function::{ArcTester, Tester};
use std::thread;
let shared = ArcTester::new(|| true);
let clone = shared.clone();
let handle = thread::spawn(move || {
clone.test()
});
assert!(handle.join().unwrap());§Author
Hu Haixing
Structs§
- ArcTester
- Thread-safe shared ownership Tester implemented using
Arc - BoxTester
- Single ownership Tester implemented using
Box - RcTester
- Single-threaded shared ownership Tester implemented using
Rc
Traits§
- FnTester
Ops - Extension trait providing logical composition methods for closures
- Tester
- Tests whether a state or condition holds