mech_set/operations/
difference.rs

1use crate::*;
2
3use indexmap::set::IndexSet;
4use mech_core::set::MechSet;
5
6// Difference ------------------------------------------------------------------------
7
8#[derive(Debug)]
9struct SetDifferenceFxn {
10  lhs: Ref<MechSet>,
11  rhs: Ref<MechSet>,
12  out: Ref<MechSet>,
13}
14impl MechFunctionFactory for SetDifferenceFxn {
15  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
16    match args {
17      FunctionArgs::Binary(out, arg1, arg2) => {
18        let lhs: Ref<MechSet> = unsafe { arg1.as_unchecked() }.clone();
19        let rhs: Ref<MechSet> = unsafe { arg2.as_unchecked() }.clone();
20        let out: Ref<MechSet> = unsafe { out.as_unchecked() }.clone();
21        Ok(Box::new(SetDifferenceFxn { lhs, rhs, out }))
22      },
23      _ => Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: args.len() }, None).with_compiler_loc()),
24    }
25  }
26}
27impl MechFunctionImpl for SetDifferenceFxn {
28  fn solve(&self) {
29    unsafe {
30      // Get mutable reference to the output set
31      let out_ptr: &mut MechSet = &mut *(self.out.as_mut_ptr());
32
33      // Get references to lhs and rhs sets
34      let lhs_ptr: &MechSet = &*(self.lhs.as_ptr());
35      let rhs_ptr: &MechSet = &*(self.rhs.as_ptr());
36
37      // Clear the output set
38      out_ptr.set.clear();
39
40      // Compute lhs \ rhs into output
41      out_ptr.set = lhs_ptr.set.difference(&(rhs_ptr.set)).cloned().collect();
42
43      // Update metadata
44      out_ptr.num_elements = out_ptr.set.len();
45      out_ptr.kind = if out_ptr.set.len() > 0 {
46        out_ptr.set.iter().next().unwrap().kind()
47      } else {
48        ValueKind::Empty
49      };
50    }
51  }
52  fn out(&self) -> Value { Value::Set(self.out.clone()) }
53  fn to_string(&self) -> String { format!("{:#?}", self) }
54}
55#[cfg(feature = "compiler")]
56impl MechFunctionCompiler for SetDifferenceFxn {
57  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
58    let name = format!("SetDifferenceFxn");
59    compile_binop!(name, self.out, self.lhs, self.rhs, ctx, FeatureFlag::Builtin(FeatureKind::Difference) );
60  }
61}
62register_descriptor! {
63  FunctionDescriptor {
64    name: "SetDifferenceFxn",
65    ptr: SetDifferenceFxn::new,
66  }
67}
68
69fn set_difference_fxn(lhs: Value, rhs: Value) -> MResult<Box<dyn MechFunction>> {
70  match (lhs, rhs) {
71    (Value::Set(lhs), Value::Set(rhs)) => {
72      Ok(Box::new(SetDifferenceFxn {
73        lhs: lhs.clone(),
74        rhs: rhs.clone(),
75        out: Ref::new(MechSet::new(
76          lhs.borrow().kind.clone(),
77          lhs.borrow().num_elements + rhs.borrow().num_elements
78        ))
79      }))
80    },
81    x => Err(MechError2::new(
82      UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/difference".to_string() },
83      None
84    ).with_compiler_loc()),
85  }
86}
87
88pub struct SetDifference {}
89impl NativeFunctionCompiler for SetDifference {
90  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
91    if arguments.len() != 2 {
92      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: arguments.len() }, None).with_compiler_loc());
93    }
94    let lhs = arguments[0].clone();
95    let rhs = arguments[1].clone();
96    match set_difference_fxn(lhs.clone(), rhs.clone()) {
97      Ok(fxn) => Ok(fxn),
98      Err(_) => {
99        match (lhs, rhs) {
100          (Value::MutableReference(lhs), Value::MutableReference(rhs)) => { set_difference_fxn(lhs.borrow().clone(), rhs.borrow().clone()) },
101          (lhs, Value::MutableReference(rhs)) => { set_difference_fxn(lhs.clone(), rhs.borrow().clone()) },
102          (Value::MutableReference(lhs), rhs) => { set_difference_fxn(lhs.borrow().clone(), rhs.clone()) },
103          x => Err(MechError2::new(
104            UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/difference".to_string() },
105            None
106          ).with_compiler_loc()),
107        }
108      }
109    }
110  }
111}
112
113register_descriptor! {
114  FunctionCompilerDescriptor {
115    name: "set/difference",
116    ptr: &SetDifference{},
117  }
118}