Files
tines/tines-sim/src/trace.rs
T
2026-10-17 21:48:37 -07:00

74 lines
2.3 KiB
Rust

//! Contact traces: a timeline of which nodes are within range of each other.
/// A single contact window between two nodes.
///
/// Nodes `a` and `b` are in contact during the half-open interval
/// `[start_ms, end_ms)`. Contacts are symmetric: a contact recorded as
/// `(a, b)` is equivalent to `(b, a)`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Contact {
pub start_ms: u64,
pub end_ms: u64,
pub a: usize,
pub b: usize,
}
/// An ordered list of contact windows, as produced by the contact simulator.
#[derive(Clone, Debug, Default)]
pub struct ContactTrace {
pub contacts: Vec<Contact>,
}
impl ContactTrace {
/// Whether `a` and `b` are in contact at time `t`, for any contact
/// involving the pair in either order.
///
/// A contact counts during its half-open window: `start_ms <= t < end_ms`.
pub fn in_contact(&self, a: usize, b: usize, t: u64) -> bool {
self.contacts
.iter()
.any(|c| is_contact_pair(c, a, b) && in_window(c, t))
}
/// The last time any contact ends, or `0` if there are no contacts.
pub fn end(&self) -> u64 {
self.contacts.iter().map(|c| c.end_ms).max().unwrap_or(0)
}
}
/// True when `c` links `a` and `b` in either order.
fn is_contact_pair(c: &Contact, a: usize, b: usize) -> bool {
(c.a == a && c.b == b) || (c.a == b && c.b == a)
}
/// True when `t` falls inside the half-open window `[start, end)`.
fn in_window(c: &Contact, t: u64) -> bool {
c.start_ms <= t && t < c.end_ms
}
#[cfg(test)]
mod tests {
use super::{Contact, ContactTrace};
#[test]
fn in_contact_matches_both_orders() {
let mut trace = ContactTrace::default();
trace.contacts.push(Contact {
start_ms: 100,
end_ms: 200,
a: 3,
b: 7,
});
assert!(!trace.in_contact(3, 7, 50)); // before the window
assert!(trace.in_contact(3, 7, 100)); // at the start edge
assert!(trace.in_contact(7, 3, 150)); // mid-window, either order
assert!(!trace.in_contact(3, 7, 200)); // at the end edge (half-open)
assert!(!trace.in_contact(3, 7, 300)); // after the window
}
#[test]
fn end_is_zero_when_empty() {
assert_eq!(ContactTrace::default().end(), 0);
}
}