1use crate::engine::*;
2
3#[derive(Debug,Default)]
14pub struct If;
15literal!{If}
16
17impl Call for If { type Conv=cc::Syntax; }
18
19impl<Cond:Eval,T,F> SynCall< sexpr!{Cond,T,F} > for If
20where Cond::Result : IfImpl<T,F> {
21 type Result = <Cond::Result as IfImpl<T,F>>::Result;
22}
23
24impl<Cond:Eval,T,F,CQ,TQ,FQ> SynCalc< sexpr!{Cond,T,F}, sexpr!{CQ,TQ,FQ} > for If
25where Cond::Result : IfCalcImpl<T,F,TQ,FQ> {
26 type Result = <Cond::Result as IfCalcImpl<T,F,TQ,FQ>>::Result;
27 fn syn_calc(self, sexpr_pat!{_:CQ,tq:TQ,fq:FQ}:sexpr!{CQ,TQ,FQ})->Self::Result {
28 Cond::Result::calc(tq,fq)
29 }
30}
31
32pub trait IfImpl<T,F> {
33 type Result;
34}
35
36impl<T,F,Bool> IfImpl<T,F> for std::marker::PhantomData<Bool>
37where Bool: IfImpl<T,F> {
38 type Result = Bool::Result;
39}
40
41impl<T:Eval,F> IfImpl<T,F> for ::typenum::True {
42 type Result = T::Result;
43}
44
45impl<T, F:Eval> IfImpl<T,F> for ::typenum::False {
46 type Result = F::Result;
47}
48
49pub trait IfCalcImpl<T,F,QT,QF> {
50 type Result;
51 fn calc(qt:QT, qf:QF)->Self::Result;
52}
53
54impl<T,F,QT,QF,Bool> IfCalcImpl<T,F,QT,QF> for std::marker::PhantomData<Bool>
55where Bool: IfCalcImpl<T,F,QT,QF> {
56 type Result = Bool::Result;
57 fn calc(qt:QT, qf:QF)->Self::Result {
58 Bool::calc(qt,qf)
59 }
60}
61
62impl<T:Calc<QT>,F,QT,QF> IfCalcImpl<T,F,QT,QF> for ::typenum::True {
63 type Result = T::Result;
64 fn calc(qt:QT, qf:QF)->Self::Result {
65 ::std::mem::drop(qf);
67 T::calc(qt)
68 }
69}
70
71impl<T,F:Calc<QF>,QT,QF> IfCalcImpl<T,F,QT,QF> for ::typenum::False {
72 type Result = F::Result;
73 fn calc(qt:QT, qf:QF)->Self::Result {
74 ::std::mem::drop(qt);
76 F::calc(qf)
77 }
78}
79
80#[test]
81fn test() {
82 #[derive(Eq,PartialEq,Debug)] struct A;
83 #[derive(Eq,PartialEq,Debug)] struct B;
84
85 use typenum::{True,False};
86
87 let _:eval!{If, True, @A, B} = A;
90 let _:eval!{If, False, A, @B} = B;
91
92 assert_eq!(A, calc!{If, {crate::ops::Is, False, False}, @A=A, B});
93}
94
95#[derive(Debug,Default)]
96pub struct CondNoMatch;
97literal!{ CondNoMatch }
98
99#[derive(Debug,Default)]
113pub struct Cond;
114defmacro!{ Cond {
115 () { } => {super::Ret, CondNoMatch};
116 (Test, Res, Else) { {Test, Res}; Else } => {If, Test, Res, {Cond; Else}};
117}}
118
119impl<Test,Res,Else, QTest,QRes,QElse>
120SynCalc< sexpr!{{Test,Res}; Else}, sexpr!{{QTest,QRes};QElse} > for Cond
121where sexpr!{If,Test,Res,{Cond; Else}}: Calc<sexpr!{If,QTest,QRes,{Cond;QElse}}>
122{
123 type Result = <sexpr!{If,Test,Res,{Cond; Else}} as Calc<sexpr!{If,QTest,QRes,{Cond;QElse}}>>::Result;
124 fn syn_calc(self, sexpr_pat!{{qtest:QTest,qres:QRes}; qelse:QElse}: sexpr!{{QTest,QRes};QElse})->Self::Result {
125 <sexpr!{If,Test,Res,{Cond; Else}} as Calc<sexpr!{If,QTest,QRes,{Cond;QElse}}>>::calc(sexpr_val!{If,qtest,qres,@{Cond;qelse}})
126 }
127}
128
129#[test]
130fn test_cond() {
131 #[derive(Debug,Default,Eq,PartialEq)] struct A;
132 #[derive(Debug,Default,Eq,PartialEq)] struct B;
133 #[derive(Debug,Default,Eq,PartialEq)] struct C(u32);
134 struct NoEvalImpl;
135 literal!{A; B; C};
136
137 use typenum::{True,False};
138 use crate::ops::Is;
139
140 assert_type_eq!{ B, eval!{ Cond,
141 {False, NoEvalImpl},
142 {True, B},
143 {True, C}
144 }};
145
146 type Test=B;
147 assert_type_eq!{ C, eval!{ Cond,
148 {{Is, Test, A}, B},
149 {{Is, Test, B}, C},
150 {{Is, Test, C}, A}
151 }};
152
153 assert_eq!{ C(42), calc!{ Cond,
154 {{Is, Test, A}, B},
155 {{Is, Test, B}, @C=C(42)},
156 {{Is, Test, C}, A}
157 }};
158
159}
160