use std::time::Duration;
use runifold_core::{CancellationToken, Instant, InvocationId, RunContext, RunId};
use crate::RetrievalError;
#[derive(Clone, Debug)]
pub struct RetrievalContext {
invocation_id: InvocationId,
run_id: Option<RunId>,
deadline: Option<Instant>,
cancellation: CancellationToken,
}
impl RetrievalContext {
pub fn new() -> Self {
Self {
invocation_id: InvocationId::new(),
run_id: None,
deadline: None,
cancellation: CancellationToken::new(),
}
}
pub fn for_run(run: &RunContext) -> Self {
Self {
invocation_id: InvocationId::new(),
run_id: Some(run.run_id()),
deadline: run.deadline(),
cancellation: run.cancellation().child_token(),
}
}
pub const fn invocation_id(&self) -> InvocationId {
self.invocation_id
}
pub const fn run_id(&self) -> Option<RunId> {
self.run_id
}
pub const fn deadline(&self) -> Option<Instant> {
self.deadline
}
pub fn remaining(&self) -> Option<Duration> {
self.deadline
.map(|deadline| deadline.saturating_duration_since(Instant::now()))
}
pub const fn cancellation(&self) -> &CancellationToken {
&self.cancellation
}
pub fn check_live(&self) -> Result<(), RetrievalError> {
if self.cancellation.is_cancelled() {
return Err(RetrievalError::Cancelled);
}
if self
.remaining()
.is_some_and(|remaining| remaining.is_zero())
{
return Err(RetrievalError::DeadlineExceeded);
}
Ok(())
}
#[must_use]
pub fn with_deadline(mut self, deadline: Instant) -> Self {
self.deadline = Some(
self.deadline
.map_or(deadline, |current| current.min(deadline)),
);
self
}
#[must_use]
pub fn with_cancellation(mut self, cancellation: &CancellationToken) -> Self {
self.cancellation = cancellation.child_token();
self
}
#[must_use]
pub fn child_attempt(&self) -> Self {
Self {
invocation_id: InvocationId::new(),
run_id: self.run_id,
deadline: self.deadline,
cancellation: self.cancellation.child_token(),
}
}
}
impl Default for RetrievalContext {
fn default() -> Self {
Self::new()
}
}