1use std::any::{Any, TypeId};
26
27use slotmap::new_key_type;
28
29use crate::cell::CellId;
30
31new_key_type! {
32 pub struct RequirementId;
37}
38
39type RequirementFn = Box<dyn Fn(&[&dyn Any]) -> Result<bool, anyhow::Error>>;
41
42pub struct Requirement {
52 pub(crate) inputs: Vec<CellId>,
53 pub(crate) input_types: Vec<TypeId>,
54 pub(crate) function: RequirementFn,
55}
56
57impl Requirement {
58 pub fn new<F>(inputs: Vec<CellId>, input_types: Vec<TypeId>, f: F) -> Self
66 where
67 F: Fn(&[&dyn Any]) -> Result<bool, anyhow::Error> + 'static,
68 {
69 debug_assert_eq!(inputs.len(), input_types.len());
70 Requirement {
71 inputs,
72 input_types,
73 function: Box::new(f),
74 }
75 }
76
77 pub fn from_fn_1<A, F>(input: CellId, f: F) -> Self
87 where
88 A: Any + 'static,
89 F: Fn(&A) -> Result<bool, anyhow::Error> + 'static,
90 {
91 Requirement {
92 inputs: vec![input],
93 input_types: vec![TypeId::of::<A>()],
94 function: Box::new(move |args| {
95 let a = args[0]
96 .downcast_ref::<A>()
97 .expect("type checked at add_requirement");
98 f(a)
99 }),
100 }
101 }
102
103 pub fn from_fn_2<A, B, F>(inputs: [CellId; 2], f: F) -> Self
114 where
115 A: Any + 'static,
116 B: Any + 'static,
117 F: Fn(&A, &B) -> Result<bool, anyhow::Error> + 'static,
118 {
119 Requirement {
120 inputs: inputs.to_vec(),
121 input_types: vec![TypeId::of::<A>(), TypeId::of::<B>()],
122 function: Box::new(move |args| {
123 let a = args[0]
124 .downcast_ref::<A>()
125 .expect("type checked at add_requirement");
126 let b = args[1]
127 .downcast_ref::<B>()
128 .expect("type checked at add_requirement");
129 f(a, b)
130 }),
131 }
132 }
133}
134
135pub(crate) struct RequirementData {
137 pub(crate) cell: CellId,
138 pub(crate) inputs: Vec<CellId>,
139 pub(crate) function: RequirementFn,
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
148 fn typed_adapters_preserve_order_and_errors() {
149 let mut sheet = crate::Sheet::new();
150 let a = sheet.add_cell(String::new());
151 let b = sheet.add_cell('!');
152 let predicate = Requirement::from_fn_2([a, b], |a: &String, b: &char| Ok(a.ends_with(*b)));
153 assert!((predicate.function)(&[&"yes!".to_string(), &'!']).unwrap());
154 assert!(!(predicate.function)(&[&"no?".to_string(), &'!']).unwrap());
155 let one = Requirement::from_fn_1(a, |_: &String| Err(std::io::Error::other("one").into()));
156 let two = Requirement::from_fn_2([a, b], |_: &String, _: &char| {
157 Err(std::io::Error::other("two").into())
158 });
159 assert!(
160 (one.function)(&[&String::new()])
161 .unwrap_err()
162 .downcast_ref::<std::io::Error>()
163 .is_some()
164 );
165 assert!(
166 (two.function)(&[&String::new(), &'!'])
167 .unwrap_err()
168 .downcast_ref::<std::io::Error>()
169 .is_some()
170 );
171 }
172
173 #[test]
174 fn requirement_id_is_copy() {
176 fn takes_copy<T: Copy>(_: T) {}
178 takes_copy(RequirementId::default());
179 }
180
181 #[test]
182 fn requirement_new_stores_types_and_cell_ids() {
184 use slotmap::SlotMap;
185
186 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
187 let a = map.insert(());
188 let b = map.insert(());
189
190 let requirement = Requirement::new(
191 vec![a, b],
192 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
193 |args| {
194 let x = args[0].downcast_ref::<i32>().unwrap();
195 let y = args[1].downcast_ref::<i32>().unwrap();
196 Ok(x + y <= 10)
197 },
198 );
199
200 assert_eq!(requirement.inputs, vec![a, b]);
201 assert_eq!(
202 requirement.input_types,
203 vec![TypeId::of::<i32>(), TypeId::of::<i32>()]
204 );
205
206 let x: i32 = 3;
207 let y: i32 = 4;
208 assert!((requirement.function)(&[&x, &y]).unwrap());
209 let x: i32 = 8;
210 let y: i32 = 8;
211 assert!(!(requirement.function)(&[&x, &y]).unwrap());
212 }
213
214 #[test]
215 fn from_fn_1_stores_correct_type_ids() {
217 use slotmap::SlotMap;
218
219 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
220 let a = map.insert(());
221
222 let requirement = Requirement::from_fn_1(a, |x: &i32| Ok(*x <= 5));
223
224 assert_eq!(requirement.inputs, vec![a]);
225 assert_eq!(requirement.input_types, vec![TypeId::of::<i32>()]);
226
227 let x: i32 = 3;
228 assert!((requirement.function)(&[&x]).unwrap());
229 let x: i32 = 9;
230 assert!(!(requirement.function)(&[&x]).unwrap());
231 }
232
233 #[test]
234 fn from_fn_2_stores_correct_type_ids() {
236 use slotmap::SlotMap;
237
238 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
239 let a = map.insert(());
240 let b = map.insert(());
241
242 let requirement = Requirement::from_fn_2([a, b], |x: &i32, y: &i32| Ok(x * y <= 20));
243
244 assert_eq!(requirement.inputs, vec![a, b]);
245 assert_eq!(
246 requirement.input_types,
247 vec![TypeId::of::<i32>(), TypeId::of::<i32>()]
248 );
249
250 let x: i32 = 4;
251 let y: i32 = 5;
252 assert!((requirement.function)(&[&x, &y]).unwrap());
253 let x: i32 = 5;
254 let y: i32 = 5;
255 assert!(!(requirement.function)(&[&x, &y]).unwrap());
256 }
257}