1use bytes::Bytes;
12
13use crate::abi::{EntityId, InstanceId, TypeCode};
14use crate::state::{EntityMeta, Instance};
15
16pub struct InstanceView<'a> {
18 pub(crate) instance: &'a Instance,
19}
20
21impl<'a> InstanceView<'a> {
22 pub fn id(&self) -> InstanceId {
24 self.instance.id()
25 }
26
27 pub fn entity_count(&self) -> usize {
29 self.instance.entities_len()
30 }
31
32 pub fn component_count(&self) -> usize {
34 self.instance.components_len()
35 }
36
37 pub fn local_tick(&self) -> u64 {
39 self.instance.local_tick()
40 }
41
42 pub fn entity_meta(&self, entity: EntityId) -> Option<&'a EntityMeta> {
44 self.instance.entity_meta(entity)
45 }
46
47 pub fn component(&self, entity: EntityId, type_code: TypeCode) -> Option<&'a Bytes> {
50 self.instance.component(entity, type_code)
51 }
52
53 pub fn entities(&self) -> impl Iterator<Item = (EntityId, &'a EntityMeta)> + 'a {
56 self.instance.entities_iter()
57 }
58
59 pub fn components_by_type(
64 &self,
65 type_code: TypeCode,
66 ) -> impl Iterator<Item = (EntityId, &'a Bytes)> + 'a {
67 self.instance.components_by_type_iter(type_code)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::abi::{CapabilityMask, EntityId, Principal, Tick, TypeCode};
75 use crate::state::traits::_sealed::Sealed;
76 use crate::state::{ActionCompute, ActionContext, ActionDeriv, InstanceConfig, Op};
77 use crate::Kernel;
78 use serde::{Deserialize, Serialize};
79
80 #[derive(Serialize, Deserialize)]
83 struct SpawnManyAction {
84 count: u64,
85 type_code: u32,
86 size: u64,
87 }
88 impl Sealed for SpawnManyAction {}
89 impl ActionDeriv for SpawnManyAction {
90 const TYPE_CODE: TypeCode = TypeCode(900);
91 const SCHEMA_VERSION: u32 = 1;
92 }
93 impl ActionCompute for SpawnManyAction {
94 fn compute(&self, _ctx: &ActionContext) -> Vec<Op> {
95 let mut ops = Vec::with_capacity((self.count * 2) as usize);
96 for n in 1..=self.count {
97 let entity = EntityId::new(n).unwrap();
98 ops.push(Op::SpawnEntity {
99 id: entity,
100 owner: Principal::System,
101 });
102 ops.push(Op::SetComponent {
103 entity,
104 type_code: TypeCode(self.type_code),
105 bytes: Bytes::from(vec![0xAB; self.size as usize]),
106 size: self.size,
107 });
108 }
109 ops
110 }
111 }
112
113 fn submit(k: &mut Kernel, inst: InstanceId, action: &SpawnManyAction) {
114 use crate::state::Action;
115 let bytes = Action::canonical_bytes(action);
116 k.submit(
117 inst,
118 Principal::System,
119 None,
120 CapabilityMask::SYSTEM,
121 Tick(0),
122 SpawnManyAction::TYPE_CODE,
123 bytes,
124 )
125 .expect("submit ok");
126 }
127
128 fn boot() -> (Kernel, InstanceId) {
129 let mut k = Kernel::new();
130 k.register_action::<SpawnManyAction>();
131 let inst = k.create_instance(InstanceConfig::default());
132 (k, inst)
133 }
134
135 #[test]
136 fn view_none_for_missing_instance() {
137 let k = Kernel::new();
138 let bogus = InstanceId::new(99).unwrap();
139 assert!(k.instance_view(bogus).is_none());
140 }
141
142 #[test]
143 fn view_reflects_entity_count() {
144 let (mut k, inst) = boot();
145 submit(
146 &mut k,
147 inst,
148 &SpawnManyAction {
149 count: 1,
150 type_code: 7,
151 size: 10,
152 },
153 );
154 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
155
156 let view = k.instance_view(inst).expect("view present");
157 assert_eq!(view.id(), inst);
158 assert_eq!(view.entity_count(), 1);
159 assert_eq!(view.component_count(), 1);
160 }
161
162 #[test]
163 fn view_component_bytes_match_set() {
164 let (mut k, inst) = boot();
165 submit(
166 &mut k,
167 inst,
168 &SpawnManyAction {
169 count: 1,
170 type_code: 7,
171 size: 4,
172 },
173 );
174 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
175
176 let view = k.instance_view(inst).expect("view present");
177 let comp = view
178 .component(EntityId::new(1).unwrap(), TypeCode(7))
179 .expect("component present");
180 assert_eq!(comp.as_ref(), &[0xAB, 0xAB, 0xAB, 0xAB]);
181 }
182
183 #[test]
184 fn view_entities_iter_ascending() {
185 let (mut k, inst) = boot();
186 submit(
187 &mut k,
188 inst,
189 &SpawnManyAction {
190 count: 3,
191 type_code: 7,
192 size: 1,
193 },
194 );
195 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
196
197 let view = k.instance_view(inst).expect("view present");
198 let ids: Vec<u64> = view.entities().map(|(id, _)| id.get()).collect();
199 assert_eq!(ids, vec![1, 2, 3]);
200
201 let meta = view.entity_meta(EntityId::new(2).unwrap()).expect("meta");
203 assert_eq!(meta.owner, Principal::System);
204 assert_eq!(meta.created, Tick(0));
205 }
206
207 #[test]
208 fn view_components_by_type_filter() {
209 let (mut k, inst) = boot();
211 submit(
212 &mut k,
213 inst,
214 &SpawnManyAction {
215 count: 2,
216 type_code: 7,
217 size: 1,
218 },
219 );
220 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
221 submit(
223 &mut k,
224 inst,
225 &SpawnManyAction {
226 count: 2,
227 type_code: 8,
228 size: 1,
229 },
230 );
231 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
232
233 let view = k.instance_view(inst).expect("view present");
234 assert_eq!(view.component_count(), 4);
236
237 let tc7: Vec<u64> = view
238 .components_by_type(TypeCode(7))
239 .map(|(eid, _)| eid.get())
240 .collect();
241 assert_eq!(tc7, vec![1, 2]);
242
243 let tc8: Vec<u64> = view
244 .components_by_type(TypeCode(8))
245 .map(|(eid, _)| eid.get())
246 .collect();
247 assert_eq!(tc8, vec![1, 2]);
248 }
249
250 #[test]
251 fn view_local_tick_updates_after_step() {
252 let (mut k, inst) = boot();
253 submit(
254 &mut k,
255 inst,
256 &SpawnManyAction {
257 count: 1,
258 type_code: 7,
259 size: 1,
260 },
261 );
262 let pre = k.instance_view(inst).unwrap().local_tick();
264 let _ = k.step(Tick(0), CapabilityMask::SYSTEM);
265 let post = k.instance_view(inst).unwrap().local_tick();
270 assert_eq!(pre, post);
271 }
272}