use crate::protocol::eval::*;
use crate::protocol::*;
use crate::runtime2::*;
use super::{CompCtx, CompPDL};
use super::component_ip::*;
pub enum CompScheduling {
Immediate,
Requeue,
Sleep,
Exit,
}
/// Generic representation of a component (as viewed by a scheduler).
pub(crate) trait Component {
/// Called if the component is created by another component and the messages
/// are being transferred between the two.
fn adopt_message(&mut self, comp_ctx: &mut CompCtx, message: DataMessage);
/// Called if the component receives a new message. The component is
/// responsible for deciding where that messages goes.
fn handle_message(&mut self, sched_ctx: &mut SchedulerCtx, comp_ctx: &mut CompCtx, message: Message);
/// Called if the component's routine should be executed. The return value
/// can be used to indicate when the routine should be run again.
fn run(&mut self, sched_ctx: &mut SchedulerCtx, comp_ctx: &mut CompCtx) -> Result<CompScheduling, EvalError>;
}
/// Creates a new component based on its definition. Meaning that if it is a
/// user-defined component then we set up the PDL code state. Otherwise we
/// construct a custom component. This does NOT take care of port and message
/// management.
pub(crate) fn create_component(
protocol: &ProtocolDescription,
definition_id: ProcedureDefinitionId, type_id: TypeId,
arguments: ValueGroup, num_ports: usize
) -> Box<dyn Component> {
let definition = &protocol.heap[definition_id];
debug_assert!(definition.kind == ProcedureKind::Primitive || definition.kind == ProcedureKind::Composite);
if definition.source.is_builtin() {
// Builtin component
let component = match definition.source {
ProcedureSource::CompRandomU32 => Box::new(ComponentRandomU32::new(arguments)),
_ => unreachable!(),
};
return component;
} else {
// User-defined component
let prompt = Prompt::new(
&protocol.types, &protocol.heap,
definition_id, type_id, arguments
);
let component = CompPDL::new(prompt, num_ports);
return Box::new(component);
}
}
#[inline]
pub(crate) fn port_id_from_eval(port_id: EvalPortId) -> PortId {
return PortId(port_id.id);
}
#[inline]
pub(crate) fn port_id_to_eval(port_id: PortId) -> EvalPortId {
return EvalPortId{ id: port_id.0 };
}