orx_meta/queue/builder.rs
1use crate::queue::{QueueSingle, StQueue};
2use core::marker::PhantomData;
3
4/// A type-safe builder for queues such that:
5///
6/// * `push` can only be called correct number of times with correct types,
7/// * `finish` can only be called when all elements to reach the `Target` type are pushed.
8///
9/// Further, since queues can represent any struct, `QueueBuilder` can be used as a generic builder for any struct or tuple.
10///
11/// # Example
12///
13/// In the following example, we want to build a queue of four elements of types `u32`, `bool`, `char` and `String` respectively.
14///
15/// For this, we can create a builder with `QueueBuilder::<MyQueue>::new()` where `MyQueue` is the target type to instantiate.
16///
17/// ```
18/// use orx_meta::queue::*;
19///
20/// type MyQueue = Queue<u32, Queue<bool, Queue<char, QueueSingle<String>>>>;
21///
22/// let instance = QueueBuilder::<MyQueue>::new()
23/// .push(42)
24/// .push(true)
25/// .push('x')
26/// .push("foo".to_string())
27/// .finish();
28/// assert_eq!(instance.as_tuple(), (&42, &true, &'x', &"foo".to_string()));
29/// ```
30///
31/// This provides a convenient way to build complex types without errors while getting compiler support on what to push next.
32/// However, it is not easy to hand-write the type alias for complex recursive queue types.
33/// Therefore, this builder pattern is most useful when used together with the [`queue_of`] macro.
34/// The above example could be re-written as follows with the `queue_of` macro.
35///
36/// [`queue_of`]: crate::queue_of
37///
38/// ```
39/// use orx_meta::queue::*;
40/// use orx_meta::queue_of;
41///
42/// type MyQueue = queue_of!(u32, bool, char, String);
43///
44/// let instance = QueueBuilder::<MyQueue>::new()
45/// .push(42)
46/// .push(true)
47/// .push('x')
48/// .push("foo".to_string())
49/// .finish();
50/// assert_eq!(instance.as_tuple(), (&42, &true, &'x', &"foo".to_string()));
51/// ```
52///
53/// ## Examples - Type Safety
54///
55/// Note that this builder pattern is type safe in the sense that neither of the following wrong implementations compiles.
56///
57/// Here the elements are pushed in the wrong order:
58///
59/// ```compile_fail
60/// use orx_meta::queue::*;
61/// use orx_meta::queue_of;
62///
63/// type MyQueue = queue_of!(u32, bool, char, String);
64///
65/// let instance = QueueBuilder::<MyQueue>::new()
66/// .push(true) // wrong order!
67/// .push(42)
68/// .push('x')
69/// .push("foo".to_string())
70/// .finish();
71/// assert_eq!(instance.as_tuple(), (&42, &true, &'x', &"foo".to_string()));
72/// ```
73///
74/// And here, not all elements are pushed:
75///
76/// ```compile_fail
77/// use orx_meta::queue::*;
78/// use orx_meta::queue_of;
79///
80/// type MyQueue = queue_of!(u32, bool, char, String);
81///
82/// let instance = QueueBuilder::<MyQueue>::new()
83/// .push(42)
84/// .push(true)
85/// .push('x')
86/// .finish(); // forgot to push the String
87/// assert_eq!(instance.as_tuple(), (&42, &true, &'x', &"foo".to_string()));
88/// ```
89pub struct QueueBuilder<Target>
90where
91 Target: StQueue,
92{
93 target: PhantomData<Target>,
94}
95
96impl<Target> Default for QueueBuilder<Target>
97where
98 Target: StQueue,
99{
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105impl<Target> QueueBuilder<Target>
106where
107 Target: StQueue,
108{
109 /// Creates a new empty builder for the `Target` type defined as the generic argument.
110 pub fn new() -> Self {
111 Self {
112 target: Default::default(),
113 }
114 }
115
116 /// Pushes the next `element` to build the target type.
117 pub fn push(
118 self,
119 element: Target::Front,
120 ) -> QueueBuilding<Target, Target::Back, QueueSingle<Target::Front>> {
121 QueueBuilding::new(QueueSingle::new(element))
122 }
123}
124
125pub struct QueueBuilding<Target, Remaining, Current>
126where
127 Target: StQueue,
128 Remaining: StQueue,
129 Current: StQueue,
130{
131 target: PhantomData<Target>,
132 remaining: PhantomData<Remaining>,
133 current: Current,
134}
135
136impl<Target, Remaining, Current> QueueBuilding<Target, Remaining, Current>
137where
138 Target: StQueue,
139 Remaining: StQueue,
140 Current: StQueue,
141{
142 fn new(current: Current) -> Self {
143 Self {
144 target: Default::default(),
145 remaining: Default::default(),
146 current,
147 }
148 }
149
150 /// Pushes the next `element` to build the target type.
151 pub fn push(
152 self,
153 element: Remaining::Front,
154 ) -> QueueBuilding<Target, Remaining::Back, Current::PushBack<Remaining::Front>> {
155 QueueBuilding::new(self.current.push(element))
156 }
157
158 /// Completes the builder and returns the built target type.
159 pub fn finish(self) -> Current
160 where
161 Target: StQueue<Front = Current::Front, Back = Current::Back>,
162 {
163 self.current
164 }
165}