computation_types/
control_flow.rs

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}