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_label: O,
16 op: A,
17) -> 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 v = Var::new(builder.clone(), result_label);
24 let v_source = v.new_source();
25
26 let mut term = builder.borrow_mut();
27 let _ = term.new_edge(
28 op,
29 Hyperedge {
30 sources: nodes,
31 targets: vec![v_source],
32 },
33 );
34
35 v
36}
37
38pub trait HasAdd<O, A> {
40 fn add(lhs_type: O, rhs_type: O) -> (O, A);
41}
42
43impl<O: Clone, A: HasVar + HasAdd<O, A>> Add for Var<O, A> {
44 type Output = Var<O, A>;
45
46 fn add(self, rhs: Self) -> Self::Output {
47 let (result_label, op) = A::add(self.label.clone(), rhs.label.clone());
49 operation(&self.state.clone(), &[self, rhs], result_label, op)
50 }
51}
52
53pub trait HasBitXor<O, A> {
55 fn bitxor(lhs_type: O, rhs_type: O) -> (O, A);
56}
57
58impl<O: Clone, A: HasVar + HasBitXor<O, A>> BitXor for Var<O, A> {
59 type Output = Var<O, A>;
60
61 fn bitxor(self, rhs: Self) -> Self::Output {
62 let (result_label, op) = A::bitxor(self.label.clone(), rhs.label.clone());
64 operation(&self.state.clone(), &[self, rhs], result_label, op)
65 }
66}
67
68macro_rules! define_binary_op {
70 ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
71 #[doc = r" Vars support this operator when the underlying signature has the appropriate operation."]
72 pub trait $has_trait_name<O, A> {
73 fn $fn_name(lhs_type: O, rhs_type: O) -> (O, A);
74 }
75
76 impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
77 type Output = Var<O, A>;
78
79 fn $fn_name(self, rhs: Self) -> Self::Output {
80 let (result_label, op) = A::$fn_name(self.label.clone(), rhs.label.clone());
81 operation(&self.state.clone(), &[self, rhs], result_label, op)
83 }
84 }
85 };
86}
87
88macro_rules! define_unary_op {
90 ($trait_name:ident, $fn_name:ident, $has_trait_name:ident) => {
91 #[doc = r" Vars support this unary operator when the underlying signature has the appropriate operation."]
92 pub trait $has_trait_name<O, A> {
93 fn $fn_name(operand_type: O) -> (O, A);
94 }
95
96 impl<O: Clone, A: HasVar + $has_trait_name<O, A>> $trait_name for Var<O, A> {
97 type Output = Var<O, A>;
98
99 fn $fn_name(self) -> Self::Output {
100 let (result_label, op) = A::$fn_name(self.label.clone());
101 operation(&self.state.clone(), &[self], result_label, op)
102 }
103 }
104 };
105}
106
107define_binary_op!(BitAnd, bitand, HasBitAnd);
109define_binary_op!(BitOr, bitor, HasBitOr);
110define_binary_op!(Shl, shl, HasShl);
111define_binary_op!(Shr, shr, HasShr);
112define_unary_op!(Not, not, HasNot);
113
114define_binary_op!(Mul, mul, HasMul);
116define_binary_op!(Sub, sub, HasSub);
117define_binary_op!(Div, div, HasDiv);
118define_unary_op!(Neg, neg, HasNeg);