Skip to main content

arkhe_kernel/state/
op.rs

1//! `Op` — kernel-level effect payload (ABI sub-enums).
2//!
3//! Each variant is the "what to do" intent; `Effect<S, 'i>` wraps it with
4//! authorization state, instance brand, and originating principal.
5//! Ships a flat enum; sub-categorization is reserved (deferred).
6
7use bytes::Bytes;
8use serde::{Deserialize, Serialize};
9
10use crate::abi::{EntityId, InstanceId, Principal, RouteId, Tick, TypeCode};
11
12/// Kernel-level effect intent. Each variant is "what to do"; the
13/// kernel wraps it in [`Effect`](crate::state::Effect) for
14/// authorization, then dispatches into the per-step `StepStage`.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16#[non_exhaustive]
17pub enum Op {
18    /// Register a new entity with the given id and owner.
19    SpawnEntity {
20        /// Entity id to register.
21        id: EntityId,
22        /// Owning principal — recorded in `EntityMeta`.
23        owner: Principal,
24    },
25    /// Remove an entity from the instance.
26    DespawnEntity {
27        /// Entity to remove.
28        id: EntityId,
29    },
30    /// Attach (or replace) a component on `entity` under `type_code`.
31    SetComponent {
32        /// Entity that owns the component.
33        entity: EntityId,
34        /// Component type discriminant.
35        type_code: TypeCode,
36        /// Canonical-postcard bytes of the component value.
37        bytes: Bytes,
38        /// Approximate size in bytes — used by the resource ledger
39        /// (memory budget enforcement).
40        size: u64,
41    },
42    /// Detach a component from `entity`.
43    RemoveComponent {
44        /// Entity to detach from.
45        entity: EntityId,
46        /// Component type discriminant.
47        type_code: TypeCode,
48        /// Approximate size in bytes — must match the original
49        /// `SetComponent` size for the ledger to balance.
50        size: u64,
51    },
52    /// Emit a domain event. Surfaces as `KernelEvent::DomainEventEmitted`
53    /// to observers post-commit.
54    EmitEvent {
55        /// Optional originating entity.
56        actor: Option<EntityId>,
57        /// Event type discriminant.
58        event_type_code: TypeCode,
59        /// Canonical-postcard bytes of the event payload.
60        event_bytes: Bytes,
61    },
62    /// Enqueue another action for a future tick.
63    ScheduleAction {
64        /// Tick at which the scheduled action becomes due.
65        at: Tick,
66        /// Optional originating entity.
67        actor: Option<EntityId>,
68        /// Type code of the scheduled action.
69        action_type_code: TypeCode,
70        /// Canonical-postcard bytes of the scheduled action.
71        action_bytes: Bytes,
72        /// Principal under which the scheduled action will be authorized.
73        action_principal: Principal,
74    },
75    /// Cross-instance signal. Routed by the kernel to the target
76    /// instance's IPC queue post-commit.
77    SendSignal {
78        /// Receiving instance.
79        target: InstanceId,
80        /// Route discriminant — the receiving instance dispatches by
81        /// this id.
82        route: RouteId,
83        /// Canonical-postcard bytes of the signal payload.
84        payload: Bytes,
85    },
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn op_variants_clone() {
94        let id = EntityId::new(1).unwrap();
95        let _ = Op::SpawnEntity {
96            id,
97            owner: Principal::System,
98        }
99        .clone();
100        let _ = Op::DespawnEntity { id }.clone();
101        let _ = Op::SetComponent {
102            entity: id,
103            type_code: TypeCode(1),
104            bytes: Bytes::from_static(b"x"),
105            size: 1,
106        }
107        .clone();
108        let _ = Op::RemoveComponent {
109            entity: id,
110            type_code: TypeCode(1),
111            size: 1,
112        }
113        .clone();
114        let _ = Op::EmitEvent {
115            actor: Some(id),
116            event_type_code: TypeCode(2),
117            event_bytes: Bytes::new(),
118        }
119        .clone();
120        let _ = Op::ScheduleAction {
121            at: Tick(0),
122            actor: None,
123            action_type_code: TypeCode(3),
124            action_bytes: Bytes::new(),
125            action_principal: Principal::System,
126        }
127        .clone();
128        let _ = Op::SendSignal {
129            target: InstanceId::new(1).unwrap(),
130            route: RouteId(1),
131            payload: Bytes::new(),
132        }
133        .clone();
134    }
135}