rendy_frame/cirque/
mod.rs

1//! Ring buffers for using with frames.
2
3mod command;
4
5pub use self::command::*;
6use {
7    crate::frame::{Frame, Frames},
8    std::collections::VecDeque,
9};
10
11/// Reference to one of the values in the `Cirque`.
12/// It can be in either initial or ready state.
13#[derive(Debug)]
14pub enum CirqueRef<'a, T, I = T, P = T> {
15    /// Reference to value in initial state.
16    Initial(InitialRef<'a, T, I, P>),
17
18    /// Reference to value in ready state.
19    Ready(ReadyRef<'a, T, I, P>),
20}
21
22impl<'a, T, I, P> CirqueRef<'a, T, I, P> {
23    /// Init if not in ready state.
24    pub fn or_init(self, init: impl FnOnce(I) -> T) -> ReadyRef<'a, T, I, P> {
25        match self {
26            CirqueRef::Initial(initial) => initial.init(init),
27            CirqueRef::Ready(ready) => ready,
28        }
29    }
30
31    /// Reset if not in initial state.
32    pub fn or_reset(self, reset: impl FnOnce(T) -> I) -> InitialRef<'a, T, I, P> {
33        match self {
34            CirqueRef::Initial(initial) => initial,
35            CirqueRef::Ready(ready) => ready.reset(reset),
36        }
37    }
38
39    /// Get ref index.
40    pub fn index(&self) -> usize {
41        match self {
42            CirqueRef::Initial(initial) => initial.index(),
43            CirqueRef::Ready(ready) => ready.index(),
44        }
45    }
46}
47
48/// Reference to new value in the `Cirque`.
49/// It is in initial state.
50#[derive(Debug)]
51pub struct InitialRef<'a, T, I = T, P = T> {
52    relevant: relevant::Relevant,
53    cirque: &'a mut Cirque<T, I, P>,
54    value: I,
55    frame: Frame,
56    index: usize,
57}
58
59impl<'a, T, I, P> InitialRef<'a, T, I, P> {
60    /// Init value.
61    pub fn init(self, init: impl FnOnce(I) -> T) -> ReadyRef<'a, T, I, P> {
62        ReadyRef {
63            relevant: self.relevant,
64            cirque: self.cirque,
65            value: init(self.value),
66            frame: self.frame,
67            index: self.index,
68        }
69    }
70
71    /// Get ref index.
72    pub fn index(&self) -> usize {
73        self.index
74    }
75}
76
77/// Reference to value in the `Cirque`.
78/// It is in ready state.
79#[derive(Debug)]
80pub struct ReadyRef<'a, T, I = T, P = T> {
81    relevant: relevant::Relevant,
82    cirque: &'a mut Cirque<T, I, P>,
83    value: T,
84    frame: Frame,
85    index: usize,
86}
87
88impl<'a, T, I, P> ReadyRef<'a, T, I, P> {
89    /// Init value.
90    pub fn reset(self, reset: impl FnOnce(T) -> I) -> InitialRef<'a, T, I, P> {
91        InitialRef {
92            relevant: self.relevant,
93            cirque: self.cirque,
94            value: reset(self.value),
95            frame: self.frame,
96            index: self.index,
97        }
98    }
99
100    /// Finish using this value.
101    pub fn finish(self, finish: impl FnOnce(T) -> P) {
102        self.relevant.dispose();
103        self.cirque
104            .pending
105            .push_back((finish(self.value), self.index, self.frame))
106    }
107
108    /// Get ref index.
109    pub fn index(&self) -> usize {
110        self.index
111    }
112}
113
114/// Resource cirque.
115/// It simplifies using multiple resources
116/// when same resource cannot be used simulteneously.
117#[derive(Debug)]
118pub struct Cirque<T, I = T, P = T> {
119    pending: VecDeque<(P, usize, Frame)>,
120    ready: VecDeque<(T, usize)>,
121    marker: std::marker::PhantomData<fn() -> I>,
122    counter: usize,
123}
124
125impl<T, I, P> Default for Cirque<T, I, P> {
126    fn default() -> Self {
127        Cirque {
128            pending: VecDeque::default(),
129            ready: VecDeque::default(),
130            marker: std::marker::PhantomData,
131            counter: usize::default(),
132        }
133    }
134}
135
136impl<T, I, P> Cirque<T, I, P> {
137    /// Create new empty `Cirque`
138    pub fn new() -> Self {
139        Self::default()
140    }
141
142    /// Dispose of the `Cirque`.
143    pub fn dispose(mut self, mut dispose: impl FnMut(either::Either<T, P>)) {
144        self.pending
145            .drain(..)
146            .for_each(|(value, _, _)| dispose(either::Right(value)));
147        self.ready
148            .drain(..)
149            .for_each(|(value, _)| dispose(either::Left(value)));
150    }
151
152    /// Get `CirqueRef` for specified frames range.
153    /// Allocate new instance in initial state if no ready values exist.
154    pub fn get<B: rendy_core::hal::Backend>(
155        &mut self,
156        frames: &Frames<B>,
157        alloc: impl FnOnce() -> I,
158        complete: impl Fn(P) -> T,
159    ) -> CirqueRef<'_, T, I, P> {
160        while let Some((value, index, frame)) = self.pending.pop_front() {
161            if frames.is_complete(frame) {
162                self.ready.push_back((complete(value), index));
163            } else {
164                self.pending.push_front((value, index, frame));
165                break;
166            }
167        }
168        if let Some((value, index)) = self.ready.pop_front() {
169            CirqueRef::Ready(ReadyRef {
170                relevant: relevant::Relevant,
171                cirque: self,
172                value,
173                frame: frames.next(),
174                index,
175            })
176        } else {
177            self.counter += 1;
178            let index = self.counter - 1;
179            let value = alloc();
180            CirqueRef::Initial(InitialRef {
181                relevant: relevant::Relevant,
182                index,
183                cirque: self,
184                value,
185                frame: frames.next(),
186            })
187        }
188    }
189}
190
191/// Resource cirque that depends on another one.
192/// It relies on trusted ready index instead of frame indices.
193/// It guarantees to always return same resource for same index.
194#[derive(Debug)]
195pub struct DependentCirque<T, I = T, P = T> {
196    values: Vec<either::Either<T, P>>,
197    marker: std::marker::PhantomData<fn() -> I>,
198}
199
200impl<T, I, P> Default for DependentCirque<T, I, P> {
201    fn default() -> Self {
202        DependentCirque {
203            values: Vec::default(),
204            marker: std::marker::PhantomData,
205        }
206    }
207}