use core::fmt;
use crate::{
defer::{DeferredAction, PreparedDeferredAction},
ipc::{self, Event},
pd_is_passive, Channel, Child, MessageInfo,
};
pub use core::convert::Infallible;
pub trait Handler {
type Error: fmt::Display;
fn notified(&mut self, channel: Channel) -> Result<(), Self::Error> {
panic!("unexpected notification from channel {channel:?}")
}
fn protected(
&mut self,
channel: Channel,
msg_info: MessageInfo,
) -> Result<MessageInfo, Self::Error> {
panic!("unexpected protected procedure call from channel {channel:?} with msg_info={msg_info:?}")
}
fn fault(
&mut self,
child: Child,
msg_info: MessageInfo,
) -> Result<Option<MessageInfo>, Self::Error> {
panic!("unexpected fault from protection domain {child:?} with msg_info={msg_info:?}")
}
fn take_deferred_action(&mut self) -> Option<DeferredAction> {
None
}
#[doc(hidden)]
fn run(&mut self) -> Result<Never, Self::Error> {
let mut reply_tag: Option<MessageInfo> = None;
let mut prepared_deferred_action: Option<PreparedDeferredAction> = if pd_is_passive() {
Some(ipc::forfeit_sc())
} else {
None
};
loop {
let event = match (reply_tag.take(), prepared_deferred_action.take()) {
(Some(msg_info), None) => ipc::reply_recv(msg_info),
(None, Some(action)) => ipc::nb_send_recv(action),
(None, None) => ipc::recv(),
_ => panic!("handler yielded deferred action after call to 'protected()'"),
};
match event {
Event::Notified(notified_event) => {
for channel in notified_event.iter() {
self.notified(channel)?;
}
}
Event::Protected(channel, msg_info) => {
reply_tag = Some(self.protected(channel, msg_info)?);
}
Event::Fault(child, msg_info) => {
reply_tag = self.fault(child, msg_info)?;
}
};
prepared_deferred_action = self
.take_deferred_action()
.as_ref()
.map(DeferredAction::prepare);
}
}
}
#[doc(hidden)]
pub enum Never {}
pub struct NullHandler(());
impl NullHandler {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(())
}
}
impl Handler for NullHandler {
type Error = Infallible;
}