1use std::any::{Any, TypeId};
7
8use slotmap::new_key_type;
9
10use crate::cell::CellId;
11
12new_key_type! {
13 pub struct RelationshipId;
15}
16
17type MethodFn = Box<dyn Fn(&[&dyn Any]) -> Result<Vec<Box<dyn Any>>, anyhow::Error>>;
22
23pub struct Method {
31 pub(crate) inputs: Vec<CellId>,
32 pub(crate) outputs: Vec<CellId>,
33 pub(crate) input_types: Vec<TypeId>,
34 pub(crate) output_types: Vec<TypeId>,
35 pub(crate) function: MethodFn,
36}
37
38impl Method {
39 pub fn new<F>(
45 inputs: Vec<CellId>,
46 outputs: Vec<CellId>,
47 input_types: Vec<TypeId>,
48 output_types: Vec<TypeId>,
49 f: F,
50 ) -> Self
51 where
52 F: Fn(&[&dyn Any]) -> Result<Vec<Box<dyn Any>>, anyhow::Error> + 'static,
53 {
54 debug_assert_eq!(inputs.len(), input_types.len());
55 debug_assert_eq!(outputs.len(), output_types.len());
56 Method {
57 inputs,
58 outputs,
59 input_types,
60 output_types,
61 function: Box::new(f),
62 }
63 }
64
65 pub fn from_fn_1_1<A, B, F>(input: CellId, output: CellId, f: F) -> Self
72 where
73 A: Any + 'static,
74 B: Any + 'static,
75 F: Fn(&A) -> Result<B, anyhow::Error> + 'static,
76 {
77 Method {
78 inputs: vec![input],
79 outputs: vec![output],
80 input_types: vec![TypeId::of::<A>()],
81 output_types: vec![TypeId::of::<B>()],
82 function: Box::new(move |args| {
83 let a = args[0]
84 .downcast_ref::<A>()
85 .expect("type checked at add_relationship");
86 Ok(vec![Box::new(f(a)?)])
87 }),
88 }
89 }
90
91 pub fn from_fn_2_1<A, B, C, F>(inputs: [CellId; 2], output: CellId, f: F) -> Self
99 where
100 A: Any + 'static,
101 B: Any + 'static,
102 C: Any + 'static,
103 F: Fn(&A, &B) -> Result<C, anyhow::Error> + 'static,
104 {
105 Method {
106 inputs: inputs.to_vec(),
107 outputs: vec![output],
108 input_types: vec![TypeId::of::<A>(), TypeId::of::<B>()],
109 output_types: vec![TypeId::of::<C>()],
110 function: Box::new(move |args| {
111 let a = args[0]
112 .downcast_ref::<A>()
113 .expect("type checked at add_relationship");
114 let b = args[1]
115 .downcast_ref::<B>()
116 .expect("type checked at add_relationship");
117 Ok(vec![Box::new(f(a, b)?)])
118 }),
119 }
120 }
121}
122
123pub(crate) struct RelationshipData {
125 pub(crate) methods: Vec<Method>,
126 pub(crate) adj: Vec<CellId>,
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn relationship_id_is_copy() {
137 fn takes_copy<T: Copy>(_: T) {}
138 takes_copy(RelationshipId::default());
141 }
142
143 #[test]
144 fn method_new_stores_types_and_cell_ids() {
145 use slotmap::SlotMap;
146
147 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
149 let a = map.insert(());
150 let b = map.insert(());
151 let c = map.insert(());
152
153 let method = Method::new(
154 vec![a, b],
155 vec![c],
156 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
157 vec![TypeId::of::<i32>()],
158 |args| {
159 let x = args[0].downcast_ref::<i32>().unwrap();
160 let y = args[1].downcast_ref::<i32>().unwrap();
161 Ok(vec![Box::new(x + y)])
162 },
163 );
164
165 assert_eq!(method.inputs, vec![a, b]);
166 assert_eq!(method.outputs, vec![c]);
167 assert_eq!(
168 method.input_types,
169 vec![TypeId::of::<i32>(), TypeId::of::<i32>()]
170 );
171 assert_eq!(method.output_types, vec![TypeId::of::<i32>()]);
172
173 let x: i32 = 3;
175 let y: i32 = 4;
176 let result = (method.function)(&[&x, &y]).unwrap();
177 assert_eq!(*result[0].downcast_ref::<i32>().unwrap(), 7);
178 }
179
180 #[test]
181 fn from_fn_1_1_stores_correct_type_ids() {
182 use slotmap::SlotMap;
183
184 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
185 let a = map.insert(());
186 let b = map.insert(());
187
188 let method = Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2));
189
190 assert_eq!(method.inputs, vec![a]);
191 assert_eq!(method.outputs, vec![b]);
192 assert_eq!(method.input_types, vec![TypeId::of::<i32>()]);
193 assert_eq!(method.output_types, vec![TypeId::of::<i32>()]);
194
195 let x: i32 = 5;
196 let result = (method.function)(&[&x]).unwrap();
197 assert_eq!(*result[0].downcast_ref::<i32>().unwrap(), 10);
198 }
199
200 #[test]
201 fn from_fn_2_1_stores_correct_type_ids() {
202 use slotmap::SlotMap;
203
204 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
205 let a = map.insert(());
206 let b = map.insert(());
207 let c = map.insert(());
208
209 let method = Method::from_fn_2_1([a, b], c, |x: &f64, y: &f64| Ok((*x) * (*y)));
210
211 assert_eq!(method.inputs, vec![a, b]);
212 assert_eq!(method.outputs, vec![c]);
213 assert_eq!(
214 method.input_types,
215 vec![TypeId::of::<f64>(), TypeId::of::<f64>()]
216 );
217 assert_eq!(method.output_types, vec![TypeId::of::<f64>()]);
218
219 let x: f64 = 2.0;
220 let y: f64 = 3.0;
221 let result = (method.function)(&[&x, &y]).unwrap();
222 assert_eq!(*result[0].downcast_ref::<f64>().unwrap(), 6.0);
223 }
224}