1use std::any::{Any, TypeId};
9
10use slotmap::new_key_type;
11
12use crate::cell::CellId;
13
14new_key_type! {
15 pub struct RequirementId;
17}
18
19type RequirementFn = Box<dyn Fn(&[&dyn Any]) -> Result<bool, anyhow::Error>>;
21
22pub struct Requirement {
29 pub(crate) inputs: Vec<CellId>,
30 pub(crate) input_types: Vec<TypeId>,
31 pub(crate) function: RequirementFn,
32}
33
34impl Requirement {
35 pub fn new<F>(inputs: Vec<CellId>, input_types: Vec<TypeId>, f: F) -> Self
40 where
41 F: Fn(&[&dyn Any]) -> Result<bool, anyhow::Error> + 'static,
42 {
43 debug_assert_eq!(inputs.len(), input_types.len());
44 Requirement {
45 inputs,
46 input_types,
47 function: Box::new(f),
48 }
49 }
50
51 pub fn from_fn_1<A, F>(input: CellId, f: F) -> Self
58 where
59 A: Any + 'static,
60 F: Fn(&A) -> Result<bool, anyhow::Error> + 'static,
61 {
62 Requirement {
63 inputs: vec![input],
64 input_types: vec![TypeId::of::<A>()],
65 function: Box::new(move |args| {
66 let a = args[0]
67 .downcast_ref::<A>()
68 .expect("type checked at add_requirement");
69 f(a)
70 }),
71 }
72 }
73
74 pub fn from_fn_2<A, B, F>(inputs: [CellId; 2], f: F) -> Self
82 where
83 A: Any + 'static,
84 B: Any + 'static,
85 F: Fn(&A, &B) -> Result<bool, anyhow::Error> + 'static,
86 {
87 Requirement {
88 inputs: inputs.to_vec(),
89 input_types: vec![TypeId::of::<A>(), TypeId::of::<B>()],
90 function: Box::new(move |args| {
91 let a = args[0]
92 .downcast_ref::<A>()
93 .expect("type checked at add_requirement");
94 let b = args[1]
95 .downcast_ref::<B>()
96 .expect("type checked at add_requirement");
97 f(a, b)
98 }),
99 }
100 }
101}
102
103pub(crate) struct RequirementData {
105 pub(crate) cell: CellId,
106 pub(crate) inputs: Vec<CellId>,
107 pub(crate) function: RequirementFn,
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn requirement_id_is_copy() {
116 fn takes_copy<T: Copy>(_: T) {}
117 takes_copy(RequirementId::default());
118 }
119
120 #[test]
121 fn requirement_new_stores_types_and_cell_ids() {
122 use slotmap::SlotMap;
123
124 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
125 let a = map.insert(());
126 let b = map.insert(());
127
128 let requirement = Requirement::new(
129 vec![a, b],
130 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
131 |args| {
132 let x = args[0].downcast_ref::<i32>().unwrap();
133 let y = args[1].downcast_ref::<i32>().unwrap();
134 Ok(x + y <= 10)
135 },
136 );
137
138 assert_eq!(requirement.inputs, vec![a, b]);
139 assert_eq!(
140 requirement.input_types,
141 vec![TypeId::of::<i32>(), TypeId::of::<i32>()]
142 );
143
144 let x: i32 = 3;
145 let y: i32 = 4;
146 assert!((requirement.function)(&[&x, &y]).unwrap());
147 let x: i32 = 8;
148 let y: i32 = 8;
149 assert!(!(requirement.function)(&[&x, &y]).unwrap());
150 }
151
152 #[test]
153 fn from_fn_1_stores_correct_type_ids() {
154 use slotmap::SlotMap;
155
156 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
157 let a = map.insert(());
158
159 let requirement = Requirement::from_fn_1(a, |x: &i32| Ok(*x <= 5));
160
161 assert_eq!(requirement.inputs, vec![a]);
162 assert_eq!(requirement.input_types, vec![TypeId::of::<i32>()]);
163
164 let x: i32 = 3;
165 assert!((requirement.function)(&[&x]).unwrap());
166 let x: i32 = 9;
167 assert!(!(requirement.function)(&[&x]).unwrap());
168 }
169
170 #[test]
171 fn from_fn_2_stores_correct_type_ids() {
172 use slotmap::SlotMap;
173
174 let mut map: SlotMap<CellId, ()> = SlotMap::with_key();
175 let a = map.insert(());
176 let b = map.insert(());
177
178 let requirement = Requirement::from_fn_2([a, b], |x: &i32, y: &i32| Ok(x * y <= 20));
179
180 assert_eq!(requirement.inputs, vec![a, b]);
181 assert_eq!(
182 requirement.input_types,
183 vec![TypeId::of::<i32>(), TypeId::of::<i32>()]
184 );
185
186 let x: i32 = 4;
187 let y: i32 = 5;
188 assert!((requirement.function)(&[&x, &y]).unwrap());
189 let x: i32 = 5;
190 let y: i32 = 5;
191 assert!(!(requirement.function)(&[&x, &y]).unwrap());
192 }
193}