use crate::activity;
use crate::bpmn::schema::{
ActivityType, DocumentElement, Element, EndEvent, EventBasedGateway, ExclusiveGateway,
FlowNodeType, InclusiveGateway, IntermediateCatchEvent, IntermediateThrowEvent,
ParallelGateway, ScriptTask, SequenceFlow, StartEvent,
};
use crate::event::{end_event, intermediate_catch_event, intermediate_throw_event, start_event};
use crate::gateway;
use crate::process::{self};
use factory::ParameterizedFactory;
use futures::stream::Stream;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use std::marker::PhantomData;
use thiserror::Error;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum State {
StartEvent(start_event::State),
EndEvent(end_event::State),
IntermediateThrowEvent(intermediate_throw_event::State),
IntermediateCatchEvent(intermediate_catch_event::State),
ParallelGateway(gateway::parallel::State),
ExclusiveGateway(gateway::exclusive::State),
InclusiveGateway(gateway::inclusive::State),
EventBasedGateway(gateway::event_based::State),
ScriptTask(activity::script_task::State),
ActivityState(activity::State),
}
#[derive(Error, Debug)]
pub enum StateError {
#[error("invalid state variant")]
InvalidVariant,
}
pub type IncomingIndex = usize;
pub type OutgoingIndex = usize;
pub const SMALL_INCOMING: usize = 8;
pub const SMALL_OUTGOING: usize = 8;
#[derive(Debug)]
pub enum Action {
ProbeOutgoingSequenceFlows(SmallVec<[OutgoingIndex; SMALL_OUTGOING]>),
Flow(SmallVec<[OutgoingIndex; SMALL_OUTGOING]>),
Complete,
}
pub trait FlowNode: Stream<Item = Action> + Send + Unpin {
fn set_state(&mut self, state: State) -> Result<(), StateError>;
fn get_state(&mut self) -> State;
#[allow(unused_variables)]
fn set_process(&mut self, process: process::Handle) {}
#[allow(unused_variables)]
fn sequence_flow(
&mut self,
outgoing: OutgoingIndex,
sequence_flow: &SequenceFlow,
condition_result: bool,
) {
}
#[allow(unused_variables)]
fn handle_outgoing_action(
&mut self,
index: OutgoingIndex,
action: Option<Action>,
) -> Option<Option<Action>> {
Some(action)
}
#[allow(unused_variables)]
fn incoming(&mut self, index: IncomingIndex) {}
#[allow(unused_variables)]
fn tokens(&mut self, count: usize) {}
fn element(&self) -> Box<dyn FlowNodeType>;
}
pub(crate) fn new(element: Box<dyn DocumentElement>) -> Option<Box<dyn FlowNode>> {
let e = element.element();
match e {
Element::StartEvent => make::<StartEvent, start_event::StartEvent>(element),
Element::EndEvent => make::<EndEvent, end_event::EndEvent>(element),
Element::IntermediateThrowEvent => make::<
IntermediateThrowEvent,
intermediate_throw_event::IntermediateThrowEvent,
>(element),
Element::IntermediateCatchEvent => make::<
IntermediateCatchEvent,
intermediate_catch_event::IntermediateCatchEvent,
>(element),
Element::ParallelGateway => make::<ParallelGateway, gateway::parallel::Gateway>(element),
Element::ExclusiveGateway => make::<ExclusiveGateway, gateway::exclusive::Gateway>(element),
Element::InclusiveGateway => make::<InclusiveGateway, gateway::inclusive::Gateway>(element),
Element::EventBasedGateway => {
make::<EventBasedGateway, gateway::event_based::Gateway>(element)
}
Element::ScriptTask => make_activity::<ScriptTask, activity::script_task::Task>(element),
_ => None,
}
}
fn make<E, F>(element: Box<dyn DocumentElement>) -> Option<Box<dyn FlowNode>>
where
E: DocumentElement + FlowNodeType + Clone + Default,
F: 'static + From<E> + FlowNode,
{
element
.downcast::<E>()
.ok()
.map(|e| Box::new(F::from((*e).clone())) as Box<dyn FlowNode>)
}
struct ActivityFactory<F, E>(PhantomData<(F, E)>)
where
E: DocumentElement + ActivityType + Clone + Default + Unpin,
F: 'static + From<E> + activity::Activity;
impl<F, E> Clone for ActivityFactory<F, E>
where
E: DocumentElement + ActivityType + Clone + Default + Unpin,
F: 'static + From<E> + activity::Activity,
{
fn clone(&self) -> Self {
ActivityFactory::<F, E>(PhantomData)
}
}
impl<F, E> ParameterizedFactory for ActivityFactory<F, E>
where
E: DocumentElement + ActivityType + Clone + Default + Unpin,
F: 'static + From<E> + activity::Activity,
{
type Item = F;
type Parameter = E;
fn create(&self, param: Self::Parameter) -> Self::Item {
F::from(param)
}
}
fn make_activity<E, F>(element: Box<dyn DocumentElement>) -> Option<Box<dyn FlowNode>>
where
E: DocumentElement + ActivityType + Clone + Default + Unpin,
F: 'static + From<E> + activity::Activity,
{
if let Ok(e) = element.downcast::<E>() {
Some(Box::new(activity::ActivityContainer::new(
(*e).clone(),
ActivityFactory::<F, E>(PhantomData),
)) as Box<dyn FlowNode>)
} else {
None
}
}