use serde::{
Deserialize,
Deserializer,
Serialize,
};
use thiserror::Error;
use crate::TaskId;
use crate::scheme::UrnScheme;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum TaskLineageError<S: UrnScheme> {
#[error("task {task} and parent {parent} belong to different task trees")]
TreeMismatch {
task: TaskId<S>,
parent: TaskId<S>,
},
#[error("task cannot be its own parent: {task}")]
SelfParent {
task: TaskId<S>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct TaskLineage<S: UrnScheme> {
task: TaskId<S>,
parent: TaskId<S>,
}
impl<S: UrnScheme> TaskLineage<S> {
pub fn try_new(task: TaskId<S>, parent: TaskId<S>) -> Result<Self, TaskLineageError<S>> {
if task == parent {
return Err(TaskLineageError::SelfParent { task });
}
if task.tree() != parent.tree() {
return Err(TaskLineageError::TreeMismatch { task, parent });
}
Ok(Self { task, parent })
}
#[must_use]
pub fn task(&self) -> &TaskId<S> {
&self.task
}
#[must_use]
pub fn parent(&self) -> &TaskId<S> {
&self.parent
}
#[must_use]
pub fn into_parts(self) -> (TaskId<S>, TaskId<S>) {
(self.task, self.parent)
}
}
impl<'de, S: UrnScheme> Deserialize<'de> for TaskLineage<S> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(bound = "")]
struct WireLineage<S: UrnScheme> {
task: TaskId<S>,
parent: TaskId<S>,
}
let wire = WireLineage::<S>::deserialize(deserializer)?;
Self::try_new(wire.task, wire.parent).map_err(serde::de::Error::custom)
}
}