use std::{any::TypeId, pin::Pin, sync::Arc, time::Duration};
use serde_json::Value;
#[doc(hidden)]
pub trait State: Clone + Send + Sync + 'static {}
impl<T> State for T where T: Clone + Send + Sync + 'static {}
#[doc(hidden)]
pub trait NodeBuilder<S: State> {
fn node() -> Node<S>;
}
#[doc(hidden)]
#[derive(Clone)]
pub struct Node<S: State> {
pub name: &'static str,
pub id: TypeId,
pub deps: Arc<dyn Fn() -> Vec<Node<S>> + Send + Sync + 'static>,
pub producer: Producer<S>,
}
impl<S: State> std::fmt::Debug for Node<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Node<{}>", self.name)
}
}
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[doc(hidden)]
pub type Producer<S> = Arc<
dyn Fn(Context<S>, Vec<Value>) -> BoxFuture<'static, Result<Value>> + Send + Sync + 'static,
>;
#[derive(Debug, Clone)]
pub struct Context<S: State> {
pub state: S,
pub retry: u32,
pub start: Duration,
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Error {
pub(crate) message: String,
pub(crate) retry_in: Option<Duration>,
}
impl Error {
pub fn fatal(message: impl Into<String>) -> Self {
let message = message.into();
let retry_in = None;
Self { message, retry_in }
}
pub fn with_retry(message: impl Into<String>, retry_in: Duration) -> Self {
let message = message.into();
let retry_in = Some(retry_in);
Self { message, retry_in }
}
}
#[derive(Debug, Clone)]
pub enum Output {
Done {
duration: Duration,
},
NodeFailed {
duration: Duration,
name: &'static str,
error: String,
},
NodePanic {
duration: Duration,
name: &'static str,
error: String,
},
Stopped {
duration: Duration,
},
}
impl Output {
#[must_use]
pub fn duration(&self) -> Duration {
match self {
Output::Stopped { duration }
| Output::NodePanic { duration, .. }
| Output::NodeFailed { duration, .. }
| Output::Done { duration } => *duration,
}
}
#[must_use]
pub fn is_done(&self) -> bool {
matches!(self, Self::Done { .. })
}
#[must_use]
pub fn is_stopped(&self) -> bool {
matches!(self, Self::Stopped { .. })
}
#[must_use]
pub fn is_node_failed(&self) -> bool {
matches!(self, Self::NodeFailed { .. })
}
#[must_use]
pub fn is_node_panic(&self) -> bool {
matches!(self, Self::NodePanic { .. })
}
}