arkhe_kernel/state/context.rs
1//! `ActionContext` — read-only Instance view passed to `Action::compute`.
2//!
3//! Domain authors receive this context, observe Instance state through
4//! the limited accessor surface, and return a `Vec<Op>` describing their
5//! intended effects. Mutation is forbidden — the kernel translates Ops
6//! into `StepStage` deltas, which `apply_stage` later commits.
7
8use super::instance::Instance;
9use crate::abi::{EntityId, InstanceId, Tick};
10
11/// Read-only context passed to [`ActionCompute::compute`](super::traits::ActionCompute::compute).
12/// Carries the originating actor, current tick, and a borrowed view
13/// of the instance for limited introspection.
14pub struct ActionContext<'a> {
15 /// Optional originating entity (e.g. the player who submitted the
16 /// action). `None` for system-injected actions.
17 pub actor: Option<EntityId>,
18 /// Tick at which `step()` is processing this action.
19 pub now: Tick,
20 /// `InstanceId` of the instance the action runs against.
21 pub instance_id: InstanceId,
22 pub(crate) instance: &'a Instance,
23}
24
25impl<'a> ActionContext<'a> {
26 /// Construct an `ActionContext` bound to an Instance reference.
27 /// `pub(crate)` because only the kernel scheduler dispatches actions.
28 pub(crate) fn new(
29 actor: Option<EntityId>,
30 now: Tick,
31 instance_id: InstanceId,
32 instance: &'a Instance,
33 ) -> Self {
34 Self {
35 actor,
36 now,
37 instance_id,
38 instance,
39 }
40 }
41
42 /// Number of entities currently registered in the instance.
43 #[inline]
44 pub fn entities_len(&self) -> usize {
45 self.instance.entities_len()
46 }
47
48 /// Total component count across all entities.
49 #[inline]
50 pub fn components_len(&self) -> usize {
51 self.instance.components_len()
52 }
53
54 /// Logical local tick of the instance.
55 #[inline]
56 pub fn local_tick(&self) -> u64 {
57 self.instance.local_tick()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use crate::state::InstanceConfig;
65
66 #[test]
67 fn context_accessor_matches_instance() {
68 let inst = Instance::new(InstanceId::new(7).unwrap(), InstanceConfig::default());
69 let ctx = ActionContext {
70 actor: Some(EntityId::new(1).unwrap()),
71 now: Tick(0),
72 instance_id: InstanceId::new(7).unwrap(),
73 instance: &inst,
74 };
75 assert_eq!(ctx.entities_len(), 0);
76 assert_eq!(ctx.components_len(), 0);
77 assert_eq!(ctx.local_tick(), 0);
78 assert_eq!(ctx.now, Tick(0));
79 assert_eq!(ctx.instance_id, InstanceId::new(7).unwrap());
80 assert_eq!(ctx.actor, Some(EntityId::new(1).unwrap()));
81 }
82}