use bitflags::bitflags;
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use crate::abi::{EntityId, InstanceId, RouteId, Tick, TypeCode};
use crate::state::ScheduledActionId;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum KernelEvent {
ActionExecuted {
instance: InstanceId,
action_type: TypeCode,
at: Tick,
},
ActionFailed {
instance: InstanceId,
action_type: TypeCode,
reason: Bytes,
},
EffectFailed {
instance: InstanceId,
reason: Bytes,
},
ObserverPanic {
observer_index: u16,
},
ObserverEvicted {
observer_index: u16,
panic_at_seq: u64,
panic_count_before_eviction: u32,
},
SignalDropped {
target: InstanceId,
route: RouteId,
reason: SignalDropReason,
},
ModuleForceUnloaded {
route_id: RouteId,
live_refs_at_unload: u32,
},
ActionDeferredToNextTick {
action_id: ScheduledActionId,
reason: DeferReason,
},
ObserversFlushed {
barrier_ticket: u64,
event_count: u32,
},
DomainEventEmitted {
instance: InstanceId,
actor: Option<EntityId>,
event_type_code: TypeCode,
bytes: Bytes,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum SignalDropReason {
QueueFull,
TargetNotFound,
Cancelled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum DeferReason {
SchedulerBusy,
BudgetExceeded,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ObserverHandle(
pub u16,
);
bitflags! {
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, serde::Serialize, serde::Deserialize)]
pub struct EventMask: u32 {
const ACTION_EXECUTED = 1 << 0;
const ACTION_FAILED = 1 << 1;
const EFFECT_FAILED = 1 << 2;
const OBSERVER_PANIC = 1 << 3;
const OBSERVER_EVICTED = 1 << 4;
const SIGNAL_DROPPED = 1 << 5;
const MODULE_FORCE_UNLOADED = 1 << 6;
const ACTION_DEFERRED = 1 << 7;
const OBSERVERS_FLUSHED = 1 << 8;
const DOMAIN_EVENT_EMITTED = 1 << 9;
const ALL = 0x3FF;
}
}
impl Default for EventMask {
fn default() -> Self {
Self::ALL
}
}
impl EventMask {
pub(crate) fn matches(&self, event: &KernelEvent) -> bool {
match event {
KernelEvent::ActionExecuted { .. } => self.contains(Self::ACTION_EXECUTED),
KernelEvent::ActionFailed { .. } => self.contains(Self::ACTION_FAILED),
KernelEvent::EffectFailed { .. } => self.contains(Self::EFFECT_FAILED),
KernelEvent::ObserverPanic { .. } => self.contains(Self::OBSERVER_PANIC),
KernelEvent::ObserverEvicted { .. } => self.contains(Self::OBSERVER_EVICTED),
KernelEvent::SignalDropped { .. } => self.contains(Self::SIGNAL_DROPPED),
KernelEvent::ModuleForceUnloaded { .. } => self.contains(Self::MODULE_FORCE_UNLOADED),
KernelEvent::ActionDeferredToNextTick { .. } => self.contains(Self::ACTION_DEFERRED),
KernelEvent::ObserversFlushed { .. } => self.contains(Self::OBSERVERS_FLUSHED),
KernelEvent::DomainEventEmitted { .. } => self.contains(Self::DOMAIN_EVENT_EMITTED),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kernel_event_all_variants_constructible() {
let inst = InstanceId::new(1).unwrap();
let route = RouteId(1);
let _ = KernelEvent::ActionExecuted {
instance: inst,
action_type: TypeCode(1),
at: Tick(0),
};
let _ = KernelEvent::ActionFailed {
instance: inst,
action_type: TypeCode(1),
reason: Bytes::from_static(b"r"),
};
let _ = KernelEvent::EffectFailed {
instance: inst,
reason: Bytes::new(),
};
let _ = KernelEvent::ObserverPanic { observer_index: 0 };
let _ = KernelEvent::ObserverEvicted {
observer_index: 0,
panic_at_seq: 1,
panic_count_before_eviction: 1,
};
let _ = KernelEvent::SignalDropped {
target: inst,
route,
reason: SignalDropReason::QueueFull,
};
let _ = KernelEvent::ModuleForceUnloaded {
route_id: route,
live_refs_at_unload: 0,
};
let _ = KernelEvent::ActionDeferredToNextTick {
action_id: ScheduledActionId::new(1).unwrap(),
reason: DeferReason::SchedulerBusy,
};
let _ = KernelEvent::ObserversFlushed {
barrier_ticket: 0,
event_count: 0,
};
}
#[test]
fn signal_drop_reason_copy_eq() {
let r1 = SignalDropReason::QueueFull;
let r2 = r1;
assert_eq!(r1, r2);
assert_ne!(r1, SignalDropReason::TargetNotFound);
}
#[test]
fn defer_reason_copy_distinct() {
let r1 = DeferReason::SchedulerBusy;
let r2 = DeferReason::BudgetExceeded;
assert_ne!(r1, r2);
}
#[test]
fn observer_handle_total_order() {
let h1 = ObserverHandle(1);
let h2 = ObserverHandle(2);
assert!(h1 < h2);
assert_eq!(h1, ObserverHandle(1));
}
}