use serde::{Deserialize, Serialize};
use super::content::ModelContentItem;
use super::execute::Worker;
use super::tags::{
Container, DynamicPolicy, DynamicPolicyMonoInput, DynamicPolicyMonoResult, DynamicState,
};
use super::Result;
use crate::ast2::{Position, Range};
use std::str::FromStr;
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub enum TaskStatus {
#[default]
JustCreated,
Waiting,
Eating,
}
impl ToString for TaskStatus {
fn to_string(&self) -> String {
match self {
TaskStatus::JustCreated => "created".to_string(),
TaskStatus::Waiting => "waiting".to_string(),
TaskStatus::Eating => "eating".to_string(),
}
}
}
impl FromStr for TaskStatus {
type Err = super::error::ExecuteError;
fn from_str(s: &str) -> Result<Self> {
match s {
"created" => Ok(TaskStatus::JustCreated),
"waiting" => Ok(TaskStatus::Waiting),
"eating" => Ok(TaskStatus::Eating),
_ => Err(super::error::ExecuteError::UnsupportedStatus(s.to_string())),
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct TaskState {
pub status: TaskStatus,
pub eating_end: Position,
}
pub struct TaskPolicy;
impl DynamicPolicy for TaskPolicy {
type State = TaskState;
fn mono(
inputs: DynamicPolicyMonoInput<Self::State>,
) -> Result<DynamicPolicyMonoResult<Self::State>> {
tracing::debug!("tag_task::TaskPolicy::mono\nState = {:?}", inputs.state);
let (mut result, mut residual) =
DynamicPolicyMonoResult::<Self::State>::from_inputs(inputs);
match (residual.container, residual.state.status) {
(Container::Tag(_) | Container::BeginAnchor(_, _), TaskStatus::JustCreated) => {
if !residual.readonly {
residual.state.status = TaskStatus::Waiting;
result.new_state = Some(residual.state);
result.new_output = Some(String::new());
}
result.do_next_pass = true;
}
(Container::BeginAnchor(_, _), TaskStatus::Waiting) => {
result.collector = result
.collector
.push_item(ModelContentItem::merge_downstream(
super::TASK_ANCHOR_PLACEHOLDER,
));
}
(Container::BeginAnchor(a0, a1), TaskStatus::Eating) => {
if !residual.readonly {
let (existing_output, eaten_output) = (
Range {
begin: a0.range.end,
end: a1.range.begin,
},
Range {
begin: a1.range.end,
end: residual.state.eating_end,
},
);
result.new_patches = vec![(eaten_output, String::new())];
let existing_output = Worker::get_range(residual.document, &existing_output)?;
let eaten_output = Worker::get_range(residual.document, &eaten_output)?;
result.new_output = Some(format!("{}{}", existing_output, eaten_output));
result.do_next_pass = true;
residual.state.status = TaskStatus::Waiting;
result.new_state = Some(residual.state);
};
result.do_next_pass = true;
}
_ => {}
}
Ok(result)
}
}
impl DynamicState for TaskState {
fn status_indicator(&self) -> String {
self.status.to_string()
}
}