1use std::any::Any;
21use std::rc::Rc;
22
23use smallvec::SmallVec;
24
25use crate::context::{EZombieNode, FullContext, RootContext, ContextNode, TockVec, ValueVec};
26use crate::meter::{Space, Time, PLANK_TIME_NS};
27use crate::tock::Tock;
28
29pub type ReplayFn = Box<dyn Fn(&[*const dyn Any])>;
34
35pub type ReplayInputs = SmallVec<[(Tock, Option<Rc<dyn EZombieNode>>); 4]>;
38
39pub type DependencyVec = SmallVec<[Tock; 4]>;
43
44#[derive(Clone)]
46pub struct Replayer {
47 pub f: Rc<ReplayFn>,
48 pub inputs: TockVec,
49}
50
51impl Replayer {
52 pub fn new(f: ReplayFn, inputs: TockVec) -> Rc<Self> {
53 Rc::new(Self {
54 f: Rc::new(f),
55 inputs,
56 })
57 }
58}
59
60impl std::fmt::Debug for Replayer {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("Replayer")
63 .field("inputs", &self.inputs)
64 .finish()
65 }
66}
67
68pub struct RecordState {
70 pub start_tock: Tock,
71 pub values: ValueVec,
72 pub space_taken: Space,
73 pub dependencies: DependencyVec,
77}
78
79impl std::fmt::Debug for RecordState {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 f.debug_struct("RecordState")
82 .field("start_tock", &self.start_tock)
83 .field("values_count", &self.values.len())
84 .field("space_taken", &self.space_taken)
85 .field("dependencies_count", &self.dependencies.len())
86 .finish()
87 }
88}
89
90impl RecordState {
91 pub fn new(start_tock: Tock) -> Self {
92 Self {
93 start_tock,
94 values: ValueVec::new(),
95 space_taken: Space::ZERO,
96 dependencies: DependencyVec::new(),
97 }
98 }
99
100 pub fn push_value(&mut self, node: Rc<dyn EZombieNode>) {
101 self.space_taken += Space::from_bytes(node.size());
102 self.values.push(Some(node));
103 }
104
105 #[inline]
109 pub fn register_dependency(&mut self, tock: Tock) {
110 if tock < self.start_tock {
111 self.dependencies.push(tock);
112 }
113 }
114}
115
116#[derive(Debug)]
123pub enum Record {
124 Root(RootRecord),
126 Head(HeadRecord),
128 Value(ValueRecord),
130}
131
132impl Record {
133 pub fn new_root(start_tock: Tock) -> Self {
135 Record::Root(RootRecord::new(start_tock))
136 }
137
138 pub fn new_head(replayer: Rc<Replayer>, start_tock: Tock, start_time: Time) -> Self {
140 Record::Head(HeadRecord::new(replayer, start_tock, start_time))
141 }
142
143 pub fn new_value(result_tock: Tock, context_start_tock: Tock) -> Self {
145 Record::Value(ValueRecord::new(result_tock, context_start_tock))
146 }
147
148 pub fn start_tock(&self) -> Tock {
150 match self {
151 Record::Root(r) => r.state.start_tock,
152 Record::Head(r) => r.state.start_tock,
153 Record::Value(r) => r.result_tock,
154 }
155 }
156
157 pub fn values(&self) -> &[Option<Rc<dyn EZombieNode>>] {
159 match self {
160 Record::Root(r) => &r.state.values,
161 Record::Head(r) => &r.state.values,
162 Record::Value(_) => &[],
163 }
164 }
165
166 pub fn push_value(&mut self, node: Rc<dyn EZombieNode>) {
168 match self {
169 Record::Root(r) => r.state.push_value(node),
170 Record::Head(r) => r.state.push_value(node),
171 Record::Value(_) => panic!("ValueRecord cannot push values"),
172 }
173 }
174
175 pub fn register_dependency(&mut self, tock: Tock) {
177 match self {
178 Record::Root(r) => r.state.register_dependency(tock),
179 Record::Head(r) => r.state.register_dependency(tock),
180 Record::Value(_) => {} }
182 }
183
184 pub fn dependencies(&self) -> &[Tock] {
186 match self {
187 Record::Root(r) => &r.state.dependencies,
188 Record::Head(r) => &r.state.dependencies,
189 Record::Value(_) => &[],
190 }
191 }
192
193 pub fn space_taken(&self) -> Space {
195 match self {
196 Record::Root(r) => r.state.space_taken,
197 Record::Head(r) => r.state.space_taken,
198 Record::Value(_) => Space::ZERO,
199 }
200 }
201
202 pub fn is_head(&self) -> bool {
204 matches!(self, Record::Head(_))
205 }
206
207 pub fn is_value(&self) -> bool {
209 matches!(self, Record::Value(_))
210 }
211
212 pub fn is_tailcall(&self) -> bool {
214 matches!(self, Record::Head(_))
215 }
216
217 pub fn get_result_tock(&self) -> Option<Tock> {
219 match self {
220 Record::Value(r) => Some(r.result_tock),
221 _ => None,
222 }
223 }
224
225 pub fn get_context_start_tock(&self) -> Option<Tock> {
227 match self {
228 Record::Value(r) => Some(r.context_start_tock),
229 _ => None,
230 }
231 }
232
233 pub fn get_replayer(&self) -> Option<Rc<Replayer>> {
235 match self {
236 Record::Head(r) => Some(r.replayer.clone()),
237 _ => None,
238 }
239 }
240
241 pub fn suspend(
250 &mut self,
251 replayer: Rc<Replayer>,
252 current_tock: Tock,
253 akasha_insert: &mut dyn FnMut(Tock, Rc<dyn ContextNode>),
254 heap_push: Option<&mut dyn FnMut(Rc<FullContext>)>,
255 ) -> Option<(TockVec, crate::union_find::UF)> {
256 match self {
257 Record::Root(r) => {
258 let ctx = RootContext::new_with_values(
260 r.state.start_tock,
261 std::mem::take(&mut r.state.values),
262 r.state.space_taken,
263 Some(replayer),
264 );
265 akasha_insert(r.state.start_tock, ctx);
266 None
267 }
268 Record::Head(r) => {
269 let deps: TockVec = std::mem::take(&mut r.state.dependencies);
273 let ctx = FullContext::new(
274 r.state.start_tock,
275 current_tock,
276 std::mem::take(&mut r.state.values),
277 r.state.space_taken,
278 Time::from_duration(std::time::Duration::from_nanos(PLANK_TIME_NS)),
279 r.replayer.clone(),
280 deps.clone(),
281 );
282 let forward_uf = *ctx.forward_uf();
284 akasha_insert(r.state.start_tock, ctx.clone());
285 if let Some(push_fn) = heap_push {
286 push_fn(ctx);
287 }
288 Some((deps, forward_uf))
289 }
290 Record::Value(_) => panic!("ValueRecord cannot be suspended"),
291 }
292 }
293
294 pub fn resume(&mut self, new_tock: Tock) {
296 match self {
297 Record::Root(r) => {
298 r.state = RecordState::new(new_tock);
299 }
300 Record::Head(r) => {
301 r.state = RecordState::new(new_tock);
302 }
303 Record::Value(_) => panic!("ValueRecord cannot be resumed"),
304 }
305 }
306
307 pub fn complete(
312 &mut self,
313 current_tock: Tock,
314 replayer: Option<Rc<Replayer>>,
315 akasha_insert: &mut dyn FnMut(Tock, Rc<dyn ContextNode>),
316 heap_push: &mut dyn FnMut(Rc<FullContext>),
317 ) -> Option<(TockVec, crate::union_find::UF)> {
318 match self {
319 Record::Root(_) => panic!("RootRecord cannot be completed"),
320 Record::Head(r) => {
321 let deps: TockVec = std::mem::take(&mut r.state.dependencies);
322 let ctx = FullContext::new(
323 r.state.start_tock,
324 current_tock,
325 std::mem::take(&mut r.state.values),
326 r.state.space_taken,
327 Time::from_duration(std::time::Duration::from_nanos(PLANK_TIME_NS)),
328 replayer.unwrap_or_else(|| r.replayer.clone()),
329 deps.clone(),
330 );
331 let forward_uf = *ctx.forward_uf();
333 akasha_insert(r.state.start_tock, ctx.clone());
334 heap_push(ctx);
335 Some((deps, forward_uf))
336 }
337 Record::Value(_) => {
338 None
340 }
341 }
342 }
343
344 pub fn prepare_replay(
347 &mut self,
348 get_input: &mut dyn FnMut(Tock) -> Option<Rc<dyn EZombieNode>>,
349 ) -> (Rc<Replayer>, ReplayInputs) {
350 match self {
351 Record::Root(_) => panic!("RootRecord cannot replay"),
352 Record::Head(r) => {
353 if r.played {
354 panic!("HeadRecord already played");
355 }
356 let mut inputs = ReplayInputs::new();
357 for &input_tock in r.replayer.inputs.iter() {
358 let node = get_input(input_tock);
359 inputs.push((input_tock, node));
360 }
361 r.played = true;
362 (r.replayer.clone(), inputs)
363 }
364 Record::Value(_) => panic!("ValueRecord cannot replay"),
365 }
366 }
367}
368
369#[derive(Debug)]
373pub struct RootRecord {
374 state: RecordState,
375}
376
377impl RootRecord {
378 pub fn new(start_tock: Tock) -> Self {
379 Self {
380 state: RecordState::new(start_tock),
381 }
382 }
383}
384
385#[derive(Debug)]
387pub struct HeadRecord {
388 state: RecordState,
389 replayer: Rc<Replayer>,
390 #[allow(dead_code)]
391 start_time: Time,
392 played: bool,
393}
394
395impl HeadRecord {
396 pub fn new(replayer: Rc<Replayer>, start_tock: Tock, start_time: Time) -> Self {
399 let mut state = RecordState::new(start_tock);
400
401 for &input_tock in &replayer.inputs {
403 state.register_dependency(input_tock);
404 }
405
406 Self {
407 state,
408 replayer,
409 start_time,
410 played: false,
411 }
412 }
413}
414
415#[derive(Debug)]
417pub struct ValueRecord {
418 result_tock: Tock,
419 context_start_tock: Tock,
420}
421
422impl ValueRecord {
423 pub fn new(result_tock: Tock, context_start_tock: Tock) -> Self {
424 Self { result_tock, context_start_tock }
425 }
426
427 pub fn context_start_tock(&self) -> Tock {
428 self.context_start_tock
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use crate::context::ZombieNode;
436 use crate::meter::Time;
437
438 #[test]
439 fn test_root_record() {
440 let record = Record::new_root(Tock(0));
441 assert_eq!(record.start_tock(), Tock(0));
442 assert!(record.values().is_empty());
443 assert!(!record.is_head());
444 assert!(!record.is_value());
445 }
446
447 #[test]
448 fn test_value_record() {
449 let record = Record::new_value(Tock(42), Tock(40));
450 assert!(record.is_value());
451 assert_eq!(record.get_result_tock(), Some(Tock(42)));
452 assert_eq!(record.get_context_start_tock(), Some(Tock(40)));
453 }
454
455 #[test]
461 fn test_record_state_dependency_filtering() {
462 let mut state = RecordState::new(Tock(10));
463
464 state.register_dependency(Tock(5));
466 state.register_dependency(Tock(0));
467
468 state.register_dependency(Tock(10)); state.register_dependency(Tock(15)); assert_eq!(state.dependencies.len(), 2);
474 assert!(state.dependencies.contains(&Tock(5)));
475 assert!(state.dependencies.contains(&Tock(0)));
476 }
477
478 #[test]
480 fn test_record_space_tracking() {
481 let mut record = Record::new_root(Tock(0));
482
483 assert_eq!(record.space_taken().as_bytes(), 0);
484
485 let node1 = ZombieNode::new(Tock(1), vec![0u8; 100]);
487 let node2 = ZombieNode::new(Tock(2), vec![0u8; 200]);
488
489 record.push_value(node1 as Rc<dyn crate::context::EZombieNode>);
490 assert!(record.space_taken().as_bytes() >= 100);
491
492 let space_after_first = record.space_taken().as_bytes();
493 record.push_value(node2 as Rc<dyn crate::context::EZombieNode>);
494 assert!(record.space_taken().as_bytes() >= space_after_first + 200);
495 }
496
497 #[test]
499 fn test_head_record_replayer() {
500 let inputs = {
501 let mut v = TockVec::new();
502 v.push(Tock(1));
503 v.push(Tock(5));
504 v
505 };
506
507 let replayer = Replayer::new(
508 Box::new(|_| {}),
509 inputs.clone(),
510 );
511
512 let record = Record::new_head(
513 replayer.clone(),
514 Tock(10),
515 Time::ZERO,
516 );
517
518 assert!(record.is_head());
519 assert!(!record.is_value());
520 assert_eq!(record.start_tock(), Tock(10));
521
522 let got_replayer = record.get_replayer();
524 assert!(got_replayer.is_some());
525 assert_eq!(got_replayer.unwrap().inputs.len(), 2);
526
527 let deps = record.dependencies();
529 assert_eq!(deps.len(), 2);
530 assert!(deps.contains(&Tock(1)));
531 assert!(deps.contains(&Tock(5)));
532 }
533
534 #[test]
536 fn test_value_record_is_terminal() {
537 let record = Record::new_value(Tock(42), Tock(40));
538
539 assert!(record.values().is_empty());
541
542 assert!(record.dependencies().is_empty());
544
545 assert_eq!(record.space_taken().as_bytes(), 0);
547
548 assert!(record.get_replayer().is_none());
550 }
551}
552