mech_set/modify/
insert.rs

1
2use crate::*;
3
4use indexmap::set::IndexSet;
5use mech_core::set::MechSet;
6
7// Insert ------------------------------------------------------------------------
8
9#[derive(Debug)]
10struct SetInsertFxn {
11  arg1: Ref<MechSet>,
12  arg2: Ref<Value>,
13  out: Ref<MechSet>,
14}
15impl MechFunctionFactory for SetInsertFxn {
16  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
17    match args {
18      FunctionArgs::Binary(out, arg1, arg2) => {
19        let arg1: Ref<MechSet> = unsafe { arg1.as_unchecked() }.clone();
20        let arg2: Ref<Value> = unsafe { arg2.as_unchecked() }.clone();
21        let out: Ref<MechSet> = unsafe { out.as_unchecked() }.clone();
22        Ok(Box::new(SetInsertFxn {arg1, arg2, out }))
23      },
24      _ => Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: args.len() }, None).with_compiler_loc()),
25    }
26  }    
27}
28
29fn match_types(type1: ValueKind, type2: ValueKind) -> (bool, bool)
30{
31  match (type1, type2)
32  {
33    (ValueKind::Set(k1, s1), ValueKind::Set(k2, s2)) => {
34      let (types_match, _) = match_types(*k1,*k2);
35      (types_match, s1==s2)
36    },
37    (ValueKind::Set(_, _), _) => (false, false),
38    (_, ValueKind::Set(_, _)) => (false, false),
39    (k1, k2) => (k1==k2, k1==k2),
40  }
41}
42
43impl MechFunctionImpl for SetInsertFxn {
44  fn solve(&self) {
45    unsafe {
46      // Get mutable reference to the output set
47      let mut out_ptr: &mut MechSet = &mut *(self.out.as_mut_ptr());
48
49      // Get references to arg1 and arg2 sets
50      let set_ptr: &MechSet = &*(self.arg1.as_ptr());
51      let elem_ptr: &Value = &*(self.arg2.as_ptr());
52
53      // Clear the output set first (optional, depending on semantics)
54      out_ptr.set.clear();
55
56      let (types_match, sizes_match) = match_types(set_ptr.kind.clone(), elem_ptr.kind().clone());
57      // Insert arg2 into arg1
58      if(types_match)
59      {
60        out_ptr.set = set_ptr.set.clone();
61        out_ptr.set.insert(elem_ptr.clone());
62        if(!sizes_match)
63        {
64          out_ptr.kind = match out_ptr.kind.clone()
65          {
66            ValueKind::Set(k1, _) => ValueKind::Set(k1, None),
67            _ => ValueKind::Empty
68          }
69        }
70      }
71      // Update metadata
72      out_ptr.num_elements = out_ptr.set.len();
73      if(types_match && sizes_match)
74      {
75        out_ptr.kind = set_ptr.kind.clone();
76      }
77    }
78  }
79  fn out(&self) -> Value { Value::Set(self.out.clone()) }
80  fn to_string(&self) -> String { format!("{:#?}", self) }
81}
82#[cfg(feature = "compiler")]
83impl MechFunctionCompiler for SetInsertFxn {
84  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
85    let name = format!("SetInsertFxn");
86    compile_binop!(name, self.out, self.arg1, self.arg2, ctx, FeatureFlag::Custom(hash_str("set/insert")) );
87  }
88}
89register_descriptor! {
90  FunctionDescriptor {
91    name: "SetInsertFxn",
92    ptr: SetInsertFxn::new,
93  }
94}
95
96fn set_insert_fxn(arg1: Value, arg2: Value) -> MResult<Box<dyn MechFunction>> {
97  match (arg1, arg2) {
98    (Value::Set(arg1), arg2) => {
99      Ok(Box::new(SetInsertFxn { arg1: arg1.clone(), arg2: Ref::new(arg2.clone()), out: Ref::new(MechSet::new(arg1.borrow().kind.clone(), arg1.borrow().num_elements + 1)) }))
100    },
101    x => Err(MechError2::new(
102      UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/insert".to_string() },
103      None
104    ).with_compiler_loc()),
105  }
106}
107
108pub struct SetInsert {}
109impl NativeFunctionCompiler for SetInsert {
110  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
111    if arguments.len() != 2 {
112      return Err(MechError2::new(IncorrectNumberOfArguments { expected: 2, found: arguments.len() }, None).with_compiler_loc());
113    }
114    let arg1 = arguments[0].clone();
115    let arg2 = arguments[1].clone();
116    match set_insert_fxn(arg1.clone(),arg2.clone()) {
117      Ok(fxn) => Ok(fxn),
118      Err(x) => {
119        match (arg1,arg2) {
120          (Value::MutableReference(arg1),Value::MutableReference(arg2)) => { set_insert_fxn(arg1.borrow().clone(),arg2.borrow().clone()) },
121          (arg1,Value::MutableReference(arg2)) => { set_insert_fxn(arg1.clone(),arg2.borrow().clone()) },
122          (Value::MutableReference(arg1),arg2) => { set_insert_fxn(arg1.borrow().clone(),arg2.clone()) },
123          x => Err(MechError2::new(
124            UnhandledFunctionArgumentKind2 { arg: (x.0.kind(), x.1.kind()), fxn_name: "set/insert".to_string() },
125            None
126          ).with_compiler_loc()),
127        }
128      }
129    }
130  }
131}
132
133register_descriptor! {
134  FunctionCompilerDescriptor {
135    name: "set/insert",
136    ptr: &SetInsert{},
137  }
138}