///|
/// Checkpoint metadata for resumable waveform processing.
pub struct ProcessingCheckpoint {
job_id : String
station : String
channel : String
next_sample : Int
total_samples : Int
stage_sequence : Int
checksum : String
complete : Bool
}
///|
/// Create the initial checkpoint for a trace.
pub fn initial_processing_checkpoint(
job_id : String,
trace : Trace,
) -> ProcessingCheckpoint {
{
job_id,
station: trace.station,
channel: trace.channel,
next_sample: 0,
total_samples: trace.npts(),
stage_sequence: 0,
checksum: waveform_checksum([]),
complete: trace.npts() == 0,
}
}
///|
/// Advance a checkpoint after processing one block.
pub fn advance_processing_checkpoint(
checkpoint : ProcessingCheckpoint,
processed_samples : Int,
stage_sequence : Int,
checksum : String,
) -> ProcessingCheckpoint {
let next = (checkpoint.next_sample + processed_samples.max(0)).min(
checkpoint.total_samples,
)
{
job_id: checkpoint.job_id,
station: checkpoint.station,
channel: checkpoint.channel,
next_sample: next,
total_samples: checkpoint.total_samples,
stage_sequence,
checksum,
complete: next >= checkpoint.total_samples,
}
}
///|
/// Validate checkpoint compatibility with a trace.
pub fn validate_processing_checkpoint(
checkpoint : ProcessingCheckpoint,
trace : Trace,
) -> Result[Unit, String] {
if checkpoint.station != trace.station || checkpoint.channel != trace.channel {
return Err("checkpoint channel does not match trace")
}
if checkpoint.total_samples != trace.npts() {
return Err("checkpoint sample count does not match trace")
}
if checkpoint.next_sample < 0 ||
checkpoint.next_sample > checkpoint.total_samples {
return Err("checkpoint cursor is outside trace bounds")
}
Ok(())
}
///|
/// Return the remaining half-open range for a checkpoint.
pub fn checkpoint_remaining_range(
checkpoint : ProcessingCheckpoint,
) -> (Int, Int) {
(checkpoint.next_sample, checkpoint.total_samples)
}
///|
/// Export checkpoints to a stable text record.
pub fn processing_checkpoint_text(checkpoint : ProcessingCheckpoint) -> String {
"job=" +
checkpoint.job_id +
" station=" +
checkpoint.station +
" channel=" +
checkpoint.channel +
" next=" +
checkpoint.next_sample.to_string() +
" total=" +
checkpoint.total_samples.to_string() +
" stage=" +
checkpoint.stage_sequence.to_string() +
" checksum=" +
checkpoint.checksum +
" complete=" +
checkpoint.complete.to_string()
}