use std::time::{Duration, SystemTime, UNIX_EPOCH};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Timestamp(u64);
impl Timestamp {
pub fn from_millis(millis: u64) -> Self {
Timestamp(millis)
}
pub fn now() -> Self {
Timestamp(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64,
)
}
pub fn as_millis(&self) -> u64 {
self.0
}
pub fn elapsed(&self) -> Duration {
let now = Timestamp::now();
Duration::from_millis(now.0.saturating_sub(self.0))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaskMetadata {
pub fired_at: Timestamp,
pub cooled_at: Option<Timestamp>,
pub fire_duration: Duration,
pub label: String,
}
impl TaskMetadata {
pub fn new(label: impl Into<String>) -> Self {
TaskMetadata {
fired_at: Timestamp::now(),
cooled_at: None,
fire_duration: Duration::ZERO,
label: label.into(),
}
}
pub fn fired_at(label: impl Into<String>, ts: Timestamp) -> Self {
TaskMetadata {
fired_at: ts,
cooled_at: None,
fire_duration: Duration::ZERO,
label: label.into(),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TaskOutput<T> {
pub value: T,
pub metrics: Vec<(String, f64)>,
}
impl<T> TaskOutput<T> {
pub fn new(value: T, metrics: Vec<(String, f64)>) -> Self {
TaskOutput { value, metrics }
}
pub fn simple(value: T) -> Self {
TaskOutput {
value,
metrics: vec![],
}
}
pub fn with_metric(mut self, name: impl Into<String>, value: f64) -> Self {
self.metrics.push((name.into(), value));
self
}
}
pub trait CrackleTask {
type Output;
fn fire(&self) -> TaskOutput<Self::Output>;
fn cool(
&self,
_output: &TaskOutput<Self::Output>,
_all_metrics: &[(String, Vec<(String, f64)>)],
) -> Vec<(String, f64)> {
vec![]
}
fn label(&self) -> String {
"anonymous task".to_string()
}
}