use crate::config::config_file::toml::deserialize_arr;
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TaskDep {
pub task: String,
pub args: Vec<String>,
}
impl TaskDep {
pub fn render(
&mut self,
tera: &mut tera::Tera,
tera_ctx: &tera::Context,
) -> crate::Result<&mut Self> {
self.task = tera.render_str(&self.task, tera_ctx)?;
for a in &mut self.args {
*a = tera.render_str(a, tera_ctx)?;
}
if self.args.is_empty() {
let s = self.task.clone();
let mut split = s.split_whitespace().map(|s| s.to_string());
if let Some(task) = split.next() {
self.task = task;
}
self.args = split.collect();
}
Ok(self)
}
}
impl Display for TaskDep {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.task)?;
if !self.args.is_empty() {
write!(f, " {}", self.args.join(" "))?;
}
Ok(())
}
}
impl From<String> for TaskDep {
fn from(s: String) -> Self {
s.parse().unwrap()
}
}
impl FromStr for TaskDep {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
task: s.to_string(),
args: Default::default(),
})
}
}
impl<'de> Deserialize<'de> for TaskDep {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let input: Vec<String> = deserialize_arr(deserializer)?;
if input.is_empty() {
Err(serde::de::Error::custom("Task name is required"))
} else if input.len() == 1 {
Ok(input[0].to_string().into())
} else {
Ok(Self {
task: input[0].clone(),
args: input[1..].to_vec(),
})
}
}
}
impl Serialize for TaskDep {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if self.args.is_empty() {
serializer.serialize_str(&self.task)
} else {
let mut seq = serializer.serialize_seq(Some(1 + self.args.len()))?;
seq.serialize_element(&self.task)?;
for arg in &self.args {
seq.serialize_element(arg)?;
}
seq.end()
}
}
}
mod tests {
#[allow(unused_imports)] use super::*;
#[test]
fn test_task_dep_from_str() {
let td: TaskDep = "task".parse().unwrap();
assert_eq!(td.task, "task");
assert!(td.args.is_empty());
}
#[test]
fn test_task_dep_display() {
let td = TaskDep {
task: "task".to_string(),
args: vec!["arg1".to_string(), "arg2".to_string()],
};
assert_eq!(td.to_string(), "task arg1 arg2");
}
#[test]
fn test_task_dep_deserialize() {
let td: TaskDep = serde_json::from_str(r#""task""#).unwrap();
assert_eq!(td.task, "task");
assert!(td.args.is_empty());
assert_eq!(&serde_json::to_string(&td).unwrap(), r#""task""#);
let td: TaskDep = serde_json::from_str(r#"["task", "arg1", "arg2"]"#).unwrap();
assert_eq!(td.task, "task");
assert_eq!(td.args, vec!["arg1", "arg2"]);
assert_eq!(
&serde_json::to_string(&td).unwrap(),
r#"["task","arg1","arg2"]"#
);
}
}