open_hypergraphs/lax/var/
operators.rs1use crate::lax::hypergraph::Hyperedge;
2use crate::lax::open_hypergraph::OpenHypergraph;
3
4use super::var::*;
5
6use std::cell::RefCell;
7use std::ops::*;
8use std::rc::Rc;
9
10pub fn operation<O: Clone, A: HasVar>(
12 builder: &Rc<RefCell<OpenHypergraph<O, A>>>,
14 vars: &[Var<O, A>],
15 result_types: Vec<O>, op: A,
17) -> Vec<Var<O, A>> {
18 let mut nodes = Vec::with_capacity(vars.len());
19 for v in vars {
20 nodes.push(v.new_target());
21 }
22
23 let result_vars: Vec<Var<O, A>> = result_types
24 .into_iter()
25 .map(|t| Var::new(builder.clone(), t))
26 .collect();
27 let result_nodes = result_vars.iter().map(|v| v.new_source()).collect();
28
29 let mut term = builder.borrow_mut();
30 let _ = term.new_edge(
31 op,
32 Hyperedge {
33 sources: nodes,
34 targets: result_nodes,
35 },
36 );
37
38 result_vars
39}
40
41pub fn fn_operation<O: Clone, A: HasVar>(
43 builder: &Rc<RefCell<OpenHypergraph<O, A>>>,
45 vars: &[Var<O, A>],
46 result_type: O,
47 op: A,
48) -> Var<O, A> {
49 let vs = operation(builder, vars, vec![result_type], op);
50 assert_eq!(vs.len(), 1);
51 vs.into_iter().next().unwrap()
52}
53
54pub trait HasAdd<O, A> {
56 fn add(lhs_type: O, rhs_type: O) -> (O, A);
57}
58
59pub trait HasBitXor<O, A> {
61 fn bitxor(lhs_type: O, rhs_type: O) -> (O, A);
62}
63
64impl<O: Clone, A: HasVar + HasBitXor<O, A>> BitXor for Var<O, A> {
65 type Output = Var<O, A>;
66
67 fn bitxor(self, rhs: Self) -> Self::Output {
68 let (result_label, op) = A::bitxor(self.label.clone(), rhs.label.clone());
70 fn_operation(&self.state.clone(), &[self, rhs], result_label, op)
71 }
72}
73
74macro_rules! define_binary_op {
76 ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
77 #[doc = r" Vars support this operator when the underlying signature has the appropriate operation."]
78 pub trait $has_trait_name<O, A> {
79 fn $fn_name(lhs_type: O, rhs_type: O) -> (O, A);
80 }
81
82 impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
83 type Output = Var<O, A>;
84
85 fn $fn_name(self, rhs: Self) -> Self::Output {
86 let (result_label, op) = A::$fn_name(self.label.clone(), rhs.label.clone());
87 fn_operation(&self.state.clone(), &[self, rhs], result_label, op)
89 }
90 }
91 };
92}
93
94macro_rules! define_unary_op {
96 ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
97 #[doc = r" Vars support this unary operator when the underlying signature has the appropriate operation."]
98 pub trait $has_trait_name<O, A> {
99 fn $fn_name(operand_type: O) -> (O, A);
100 }
101
102 impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
103 type Output = Var<O, A>;
104
105 fn $fn_name(self) -> Self::Output {
106 let (result_label, op) = A::$fn_name(self.label.clone());
107 fn_operation(&self.state.clone(), &[self], result_label, op)
108 }
109 }
110 };
111}
112
113define_binary_op!(BitAnd, bitand, HasBitAnd);
115define_binary_op!(BitOr, bitor, HasBitOr);
116define_binary_op!(Shl, shl, HasShl);
117define_binary_op!(Shr, shr, HasShr);
118define_unary_op!(Not, not, HasNot);
119
120define_binary_op!(Mul, mul, HasMul);
122define_binary_op!(Sub, sub, HasSub);
123define_binary_op!(Div, div, HasDiv);
124define_unary_op!(Neg, neg, HasNeg);