1use core::fmt;
2
3use crate::{
4 function::Function, impl_core_ops, peano::Zero, Computation, ComputationFn, NamedArgs,
5};
6
7#[derive(Clone, Copy, Debug)]
8pub struct If<A, ArgNames, P, FTrue, FFalse>
9where
10 Self: Computation,
11{
12 pub child: A,
13 pub arg_names: ArgNames,
14 pub predicate: P,
15 pub f_true: FTrue,
16 pub f_false: FFalse,
17}
18
19impl<A, ArgNames, P, FTrue, FFalse, FDim, FItem> Computation for If<A, ArgNames, P, FTrue, FFalse>
20where
21 A: Computation,
22 P: ComputationFn<Dim = Zero, Item = bool>,
23 FTrue: ComputationFn<Dim = FDim, Item = FItem>,
24 FFalse: ComputationFn<Dim = FDim, Item = FItem>,
25{
26 type Dim = FDim;
27 type Item = FItem;
28}
29
30impl<A, ArgNames, P, FTrue, FFalse> ComputationFn for If<A, ArgNames, P, FTrue, FFalse>
31where
32 Self: Computation,
33 A: ComputationFn,
34 If<A::Filled, ArgNames, P, FTrue, FFalse>: Computation,
35{
36 type Filled = If<A::Filled, ArgNames, P, FTrue, FFalse>;
37
38 fn fill(self, named_args: NamedArgs) -> Self::Filled {
39 If {
40 child: self.child.fill(named_args),
41 arg_names: self.arg_names,
42 predicate: self.predicate,
43 f_true: self.f_true,
44 f_false: self.f_false,
45 }
46 }
47
48 fn arg_names(&self) -> crate::Names {
49 self.child.arg_names()
50 }
51}
52
53impl_core_ops!(If<A, ArgNames, P, FTrue, FFalse>);
54
55impl<A, ArgNames, P, FTrue, FFalse> fmt::Display for If<A, ArgNames, P, FTrue, FFalse>
56where
57 Self: Computation,
58 A: fmt::Display,
59 ArgNames: fmt::Debug,
60 P: fmt::Display,
61 FTrue: fmt::Display,
62 FFalse: fmt::Display,
63{
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 write!(
66 f,
67 "let {:?} = {}; if {} {{ {} }} else {{ {} }})",
68 self.arg_names, self.child, self.predicate, self.f_true, self.f_false
69 )
70 }
71}
72
73#[derive(Clone, Copy, Debug)]
74pub struct LoopWhile<A, ArgNames, F, P>
75where
76 Self: Computation,
77{
78 pub child: A,
79 pub arg_names: ArgNames,
80 pub f: F,
81 pub predicate: P,
82}
83
84impl<A, ArgNames, F, P> Computation for LoopWhile<A, ArgNames, F, P>
85where
86 A: Computation,
87 F: ComputationFn<Dim = A::Dim, Item = A::Item>,
88 P: ComputationFn<Dim = Zero, Item = bool>,
89{
90 type Dim = F::Dim;
91 type Item = F::Item;
92}
93
94impl<A, ArgNames, F, P> ComputationFn for LoopWhile<A, ArgNames, F, P>
95where
96 Self: Computation,
97 A: ComputationFn,
98 LoopWhile<A::Filled, ArgNames, F, P>: Computation,
99{
100 type Filled = LoopWhile<A::Filled, ArgNames, F, P>;
101
102 fn fill(self, named_args: NamedArgs) -> Self::Filled {
103 LoopWhile {
104 child: self.child.fill(named_args),
105 arg_names: self.arg_names,
106 f: self.f,
107 predicate: self.predicate,
108 }
109 }
110
111 fn arg_names(&self) -> crate::Names {
112 self.child.arg_names()
113 }
114}
115
116impl_core_ops!(LoopWhile<A, ArgNames, F, P>);
117
118impl<A, ArgNames, F, P> fmt::Display for LoopWhile<A, ArgNames, F, P>
119where
120 Self: Computation,
121 A: fmt::Display,
122 ArgNames: fmt::Debug,
123 F: fmt::Display,
124 P: fmt::Display,
125{
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 write!(
128 f,
129 "let {:?} = {}; while !{} {{ x = {}; }})",
130 self.arg_names, self.child, self.predicate, self.f
131 )
132 }
133}
134
135#[derive(Clone, Copy, Debug)]
136pub struct Then<A, ArgNames, F>
137where
138 Self: Computation,
139{
140 pub child: A,
141 pub f: Function<ArgNames, F>,
142}
143
144impl<A, ArgNames, F> Computation for Then<A, ArgNames, F>
145where
146 A: Computation,
147 F: ComputationFn,
148{
149 type Dim = F::Dim;
150 type Item = F::Item;
151}
152
153impl<A, ArgNames, F> ComputationFn for Then<A, ArgNames, F>
154where
155 Self: Computation,
156 A: ComputationFn,
157 Then<A::Filled, ArgNames, F>: Computation,
158{
159 type Filled = Then<A::Filled, ArgNames, F>;
160
161 fn fill(self, named_args: NamedArgs) -> Self::Filled {
162 Then {
163 child: self.child.fill(named_args),
164 f: self.f,
165 }
166 }
167
168 fn arg_names(&self) -> crate::Names {
169 self.child.arg_names()
170 }
171}
172
173impl_core_ops!(Then<A, ArgNames, F>);
174
175impl<A, ArgNames, F> fmt::Display for Then<A, ArgNames, F>
176where
177 Self: Computation,
178 A: fmt::Display,
179 ArgNames: fmt::Debug,
180 F: fmt::Display,
181{
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(
184 f,
185 "let {:?} = {}; {}",
186 self.f.arg_names, self.child, self.f.body
187 )
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use proptest::prelude::*;
194 use test_strategy::proptest;
195
196 use crate::{arg, function::Function, val, Computation};
197
198 #[proptest]
199 fn if_should_display(x: i32) {
200 let inp = val!(x);
201 let arg_names = ("x",);
202 let p = arg!("x", i32).ge(val!(0));
203 let f_true = arg!("x", i32) + val!(1);
204 let f_false = arg!("x", i32) - val!(1);
205 prop_assert_eq!(
206 inp.if_(arg_names, p, f_true, f_false).to_string(),
207 format!(
208 "let {:?} = {}; if {} {{ {} }} else {{ {} }})",
209 arg_names, inp, p, f_true, f_false
210 )
211 );
212 }
213
214 #[proptest]
215 fn loop_while_should_display(x: i32) {
216 let inp = val!(x);
217 let arg_names = ("x",);
218 let f = arg!("x", i32) + val!(1);
219 let p = arg!("x", i32).lt(val!(10));
220 prop_assert_eq!(
221 inp.loop_while(arg_names, f, p).to_string(),
222 format!(
223 "let {:?} = {}; while !{} {{ x = {}; }})",
224 arg_names, inp, p, f
225 )
226 );
227 }
228
229 #[proptest]
230 fn then_should_display(x: i32) {
231 let inp = val!(x);
232 let arg_names = ("x",);
233 let f = arg!("x", i32) + val!(1);
234 prop_assert_eq!(
235 inp.then(Function::anonymous(arg_names, f)).to_string(),
236 format!("let {:?} = {}; {}", arg_names, inp, f)
237 );
238 }
239}