nimble_steps/pending_steps.rs
1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/nimble-rust/nimble
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use discoid::discoid::DiscoidBuffer;
6
7use crate::TickId;
8
9#[derive(Clone)]
10pub struct PendingStepInfo<StepT: Clone> {
11 pub step: StepT,
12 pub tick_id: TickId,
13}
14
15/// Manages a sequence of pending steps that are queued to be executed at specific ticks in a game loop.
16///
17/// This struct contains a buffer (`DiscoidBuffer`) of `PendingStepInfo` elements, designed to handle
18/// multiple steps that are pending execution across different ticks.
19///
20/// # Type Parameters
21///
22/// * `T` - Represents the type of steps stored within the buffer. As a generic parameter, it allows
23/// the `PendingSteps` struct to be flexible and applicable to various types of games or simulations
24/// where different actions are defined as steps.
25///
26/// # Fields
27///
28/// * `steps` - A circular buffer (implemented via `DiscoidBuffer`) optimized for storing and retrieving
29/// pending steps efficiently.
30///
31/// * `front_tick_id` - The tick ID of the first step in the buffer.
32///
33/// * `capacity` - The maximum number of steps that can be stored in the buffer. This parameter helps
34/// control memory usage and maintain performance.
35///
36/// # Examples
37///
38/// ```
39/// use discoid::discoid::DiscoidBuffer;
40/// use tick_id::TickId;
41/// use nimble_steps::pending_steps::PendingSteps;
42///
43/// let pending_steps = PendingSteps::<i32>::new(10, TickId::new(1));
44/// ```
45pub struct PendingSteps<T: Clone> {
46 steps: DiscoidBuffer<PendingStepInfo<T>>,
47 front_tick_id: TickId,
48 capacity: usize,
49}
50
51impl<T: Clone> PendingSteps<T> {
52 pub fn new(window_size: usize, tick_id: TickId) -> Self {
53 Self {
54 steps: DiscoidBuffer::new(window_size),
55 front_tick_id: tick_id,
56 capacity: window_size,
57 }
58 }
59
60 pub fn set(&mut self, tick_id: TickId, step: T) -> Result<(), String> {
61 let index_in_discoid = tick_id.value() - self.front_tick_id.value();
62 if index_in_discoid >= self.capacity as u32 {
63 // self.steps.capacity()
64 return Err("pending_steps: out of scope".to_string());
65 }
66
67 self.steps.set_at_index(
68 index_in_discoid as usize,
69 PendingStepInfo::<T> { step, tick_id },
70 );
71 Ok(())
72 }
73
74 pub fn discard_up_to(&mut self, tick_id: TickId) {
75 let count_in_discoid = tick_id - self.front_tick_id;
76 if count_in_discoid < 0 {
77 return;
78 }
79 self.steps.discard_front(count_in_discoid as usize);
80 }
81
82 pub fn is_empty(&self) -> bool {
83 self.steps.get_ref_at_index(0).is_none()
84 }
85
86 pub fn pop(&mut self) -> PendingStepInfo<T> {
87 let value = self.steps.get_ref_at_index(0).unwrap().clone();
88 self.steps.discard_front(1);
89 value
90 }
91
92 pub fn front_tick_id(&self) -> Option<TickId> {
93 self.steps.get_ref_at_index(0).map(|info| info.tick_id)
94 }
95}