///|
/// Select samples in `[start_seconds, end_seconds)`. A zero-width interval is
/// valid and returns an empty caller-owned snapshot. The row and shared
/// channel-value budgets are checked before output arrays are copied.
pub fn Recording::window(
self : Recording,
start_seconds : Double,
end_seconds : Double,
max_rows? : Int = 10000,
) -> Window raise ComtradeError {
if !finite(start_seconds) ||
!finite(end_seconds) ||
start_seconds > end_seconds {
raise Rejected("window", 0, "window bounds must be finite and ordered")
}
if max_rows <= 0 || max_rows > 200000 {
raise Rejected("window", 0, "max_rows must be in 1..200000")
}
let mut selected_count = 0
for sample in self.rows {
if sample.time_seconds >= start_seconds && sample.time_seconds < end_seconds {
selected_count += 1
}
}
if selected_count > max_rows {
raise Rejected(
"window", 0, "selected rows exceed max_rows; no truncation performed",
)
}
let total_channels = self.analog.length() + self.digital.length()
if selected_count * total_channels > 2000000 {
raise Rejected(
"capacity", 0, "window exceeds shared 2,000,000 channel-value budget",
)
}
let samples : Array[Sample] = []
for sample in self.rows {
if sample.time_seconds >= start_seconds && sample.time_seconds < end_seconds {
samples.push({
sample_number: sample.sample_number,
raw_ticks: sample.raw_ticks,
time_seconds: sample.time_seconds,
analog_raw: sample.analog_raw.copy(),
status: sample.status.copy(),
})
}
}
{
start_seconds,
end_seconds,
analog_channels: self.analog.copy(),
status_channels: self.digital.copy(),
samples,
}
}