use std::ptr::null;
use super::handlers::Handlers;
use super::messages::{ShutdownMessage, SHUTDOWN_HANDLER};
use super::tag::AbstractProcessTag;
use super::{AbstractProcess, Config, StartupError};
use crate::mailbox::LINK_DIED;
use crate::panic::{catch_panic, Panicked};
use crate::serializer::CanSerialize;
use crate::{host, Mailbox, Process, Tag};
type ParentProcessRef<AP> =
Process<Result<(), StartupError<AP>>, <AP as AbstractProcess>::Serializer>;
pub(crate) fn entry<AP: AbstractProcess>(
(parent, init_tag, arg): (ParentProcessRef<AP>, Tag, AP::Arg),
_: Mailbox<(), AP::Serializer>, ) where
AP::Serializer: CanSerialize<()>,
AP::Serializer: CanSerialize<ShutdownMessage<AP::Serializer>>,
{
let mut state = match startup::<AP>(arg) {
Ok(state) => {
parent.tag_send(init_tag, Ok(()));
state
}
Err(err) => {
parent.tag_send(init_tag, Err(err));
return;
}
};
let shutdown_tag = loop_and_handle::<AP>(&mut state);
shutdown::<AP>(shutdown_tag, state);
}
fn startup<AP: AbstractProcess>(arg: AP::Arg) -> Result<AP::State, StartupError<AP>> {
let config = Config::new();
match catch_panic(|| AP::init(config, arg)) {
Ok(Ok(state)) => Ok(state),
Ok(Err(custom)) => Err(StartupError::Custom(custom)),
Err(Panicked) => Err(StartupError::InitPanicked),
}
}
fn loop_and_handle<AP: AbstractProcess>(state: &mut AP::State) -> Tag {
loop {
if unsafe { host::api::message::receive(null(), 0, u64::MAX) } == LINK_DIED {
let tag = unsafe { host::api::message::get_tag() };
let tag = Tag::from(tag);
AP::handle_link_death(super::State { state }, tag);
continue;
}
let tag = unsafe { host::api::message::get_tag() };
let tag = Tag::from(tag);
let (response_tag, data) = AbstractProcessTag::extract_u6_data(tag);
if data == SHUTDOWN_HANDLER {
break response_tag;
}
AP::Handlers::handle(response_tag, data, state);
}
}
fn shutdown<AP>(shutdown_tag: Tag, state: AP::State)
where
AP: AbstractProcess,
AP::Serializer: CanSerialize<()>,
AP::Serializer: CanSerialize<ShutdownMessage<AP::Serializer>>,
{
let shutdown_message: ShutdownMessage<AP::Serializer> = AP::Serializer::decode().unwrap();
AP::terminate(state);
shutdown_message.0.send_response((), shutdown_tag);
}