1use std::any::{Any, TypeId};
7use std::collections::{HashMap, HashSet};
8use std::rc::Rc;
9
10use slotmap::SlotMap;
11
12use crate::{
13 cell::{CellData, CellId, CellKind},
14 conditional::{Branch, ConditionalData, ConditionalId, MatchExpr, MatchSource},
15 error::{Error, ErrorSite},
16 filter::{Filter, FilterKind, FilterViolation},
17 planner::{Plan, PlanStep, SeedSignatures, SeedSource, Seeds},
18 relationship::{Method, RelationshipData, RelationshipId},
19 requirement::{Requirement, RequirementData, RequirementId},
20};
21
22mod cached;
23mod dependency;
24mod prerequisites;
25
26#[cfg(test)]
27use cached::ReuseStats;
28use cached::{CachedPlan, PreparedPlan};
29
30pub struct Sheet {
50 pub(crate) cells: SlotMap<CellId, CellData>,
51 pub(crate) relationships: SlotMap<RelationshipId, RelationshipData>,
52 pub(crate) changed_cells: Vec<CellId>,
53 next_strength: u64,
57 last_plan: Option<Rc<PreparedPlan>>,
62 pre_plan_cache: Option<CachedPlan>,
64 main_plan_cache: Option<CachedPlan>,
66 seed_signatures: Option<Rc<SeedSignatures>>,
68 #[cfg(test)]
70 reuse_stats: ReuseStats,
71 pub(crate) conditionals: SlotMap<ConditionalId, ConditionalData>,
73 pub(crate) conditional_relationships: HashSet<RelationshipId>,
76 requirements: SlotMap<RequirementId, RequirementData>,
78 last_requirement_violations: HashMap<CellId, Vec<RequirementId>>,
81 last_filter_violations: HashMap<CellId, FilterViolation>,
84 filter_dependents: HashMap<CellId, Vec<CellId>>,
90 guard_independent: bool,
92}
93
94enum MatchValue<'a> {
97 Ref(&'a dyn Any),
98 Owned(Box<dyn Any>),
99}
100
101impl MatchValue<'_> {
102 fn as_dyn(&self) -> &dyn Any {
104 match self {
105 MatchValue::Ref(r) => *r,
106 MatchValue::Owned(b) => b.as_ref(),
107 }
108 }
109}
110
111#[derive(Clone, PartialEq, Eq)]
117struct StepProvenance {
118 input_producers: Vec<Option<PlanStep>>,
119 seed_inputs: Vec<CellId>,
120 source_producer: Option<PlanStep>,
121 output_classes: Vec<(CellId, OutputClassification)>,
122}
123
124#[derive(Clone, Copy, PartialEq, Eq)]
126enum OutputClassification {
127 Source,
129 Derived,
131}
132
133#[derive(Default)]
135struct PlanProvenance {
136 steps: HashMap<PlanStep, StepProvenance>,
137 output_producers: HashMap<CellId, PlanStep>,
138}
139
140#[derive(Default)]
142struct PropagationStage {
143 sources: HashMap<CellId, Box<dyn Any>>,
144 source_versions: HashMap<CellId, u64>,
146 last_source_version: u64,
147 derived: HashMap<CellId, Box<dyn Any>>,
148 executed_methods: HashSet<(RelationshipId, usize)>,
149 executed_filters: HashSet<CellId>,
150 step_provenance: HashMap<PlanStep, StepProvenance>,
151 changed: Vec<CellId>,
152 changed_set: HashSet<CellId>,
153}
154
155impl PropagationStage {
156 fn effective<'a>(&'a self, cells: &'a SlotMap<CellId, CellData>, id: CellId) -> &'a dyn Any {
158 self.derived
159 .get(&id)
160 .map(|value| value.as_ref())
161 .or_else(|| self.sources.get(&id).map(|value| value.as_ref()))
162 .unwrap_or_else(|| cells[id].source.as_ref())
163 }
164
165 fn source<'a>(&'a self, cells: &'a SlotMap<CellId, CellData>, id: CellId) -> &'a dyn Any {
167 self.sources
168 .get(&id)
169 .map(|value| value.as_ref())
170 .unwrap_or_else(|| cells[id].source.as_ref())
171 }
172
173 fn seed_source<'a>(
178 &'a self,
179 cells: &'a SlotMap<CellId, CellData>,
180 id: CellId,
181 ) -> SeedSource<'a> {
182 SeedSource {
183 value: self.source(cells, id),
184 version: self.source_versions.get(&id).copied().unwrap_or(0),
185 }
186 }
187
188 fn insert_source(&mut self, id: CellId, value: Box<dyn Any>) {
190 self.last_source_version += 1;
191 self.source_versions.insert(id, self.last_source_version);
192 self.sources.insert(id, value);
193 }
194
195 fn write(&mut self, id: CellId, value: Box<dyn Any>, shadow: bool) {
197 if shadow {
198 self.derived.insert(id, value);
199 } else {
200 self.insert_source(id, value);
201 self.derived.remove(&id);
202 }
203 if self.changed_set.insert(id) {
204 self.changed.push(id);
205 }
206 }
207
208 fn reclassify(&mut self, id: CellId, shadow: bool) {
212 if shadow {
213 if let Some(value) = self.sources.remove(&id) {
214 self.source_versions.remove(&id);
215 self.derived.insert(id, value);
216 }
217 } else if let Some(value) = self.derived.remove(&id) {
218 self.insert_source(id, value);
219 }
220 }
221}
222
223impl Sheet {
224 pub fn new() -> Self {
226 Sheet {
227 cells: SlotMap::with_key(),
228 relationships: SlotMap::with_key(),
229 changed_cells: Vec::new(),
230 next_strength: 0,
231 last_plan: None,
232 pre_plan_cache: None,
233 main_plan_cache: None,
234 seed_signatures: None,
235 #[cfg(test)]
236 reuse_stats: ReuseStats::default(),
237 conditionals: SlotMap::with_key(),
238 conditional_relationships: HashSet::new(),
239 requirements: SlotMap::with_key(),
240 last_requirement_violations: HashMap::new(),
241 last_filter_violations: HashMap::new(),
242 filter_dependents: HashMap::new(),
243 guard_independent: true,
244 }
245 }
246
247 pub fn add_cell<T: Any + PartialEq + 'static>(&mut self, value: T) -> CellId {
260 self.invalidate_prepared_plans();
261 self.next_strength += 1;
262 let strength = self.next_strength | (1u64 << 63);
263 self.cells.insert(CellData {
264 source: Box::new(value),
265 derived: None,
266 type_id: TypeId::of::<T>(),
267 strength,
268 changed: false,
269 adj: Vec::new(),
270 eq_fn: |a, b| a.downcast_ref::<T>() == b.downcast_ref::<T>(),
271 filter: None,
272 kind: CellKind::Cell,
273 requirements: Vec::new(),
274 })
275 }
276
277 pub fn add_source<T: Any + PartialEq + 'static>(&mut self, value: T) -> CellId {
283 let id = self.add_cell(value);
284 self.cells[id].kind = CellKind::Source;
285 id
286 }
287
288 pub fn cell_kind(&self, id: CellId) -> Option<CellKind> {
292 self.cells.get(id).map(|c| c.kind)
293 }
294
295 pub fn add_relationship(&mut self, methods: Vec<Method>) -> Result<RelationshipId, Error> {
327 if methods.is_empty() {
328 return Err(Error::InvalidMethod { sites: vec![] });
329 }
330
331 for (idx, method) in methods.iter().enumerate() {
332 if method.outputs.is_empty() {
333 return Err(Error::InvalidMethod {
334 sites: vec![ErrorSite::MethodIndex(idx)],
335 });
336 }
337
338 if method.inputs.len() != method.input_types.len()
340 || method.outputs.len() != method.output_types.len()
341 {
342 return Err(Error::InvalidMethod {
343 sites: vec![ErrorSite::MethodIndex(idx)],
344 });
345 }
346
347 for (&cell_id, &declared) in method.inputs.iter().zip(method.input_types.iter()) {
348 let cell = self.cells.get(cell_id).ok_or(Error::InvalidId)?;
349 if cell.type_id != declared {
350 return Err(Error::TypeMismatch {
351 expected: cell.type_id,
352 found: declared,
353 sites: vec![ErrorSite::MethodIndex(idx)],
354 });
355 }
356 }
357
358 for (&cell_id, &declared) in method.outputs.iter().zip(method.output_types.iter()) {
359 let cell = self.cells.get(cell_id).ok_or(Error::InvalidId)?;
360 if cell.kind == CellKind::Source {
361 return Err(Error::InvalidCellKind {
362 sites: vec![ErrorSite::MethodIndex(idx), ErrorSite::Cell(cell_id)],
363 });
364 }
365 if cell.type_id != declared {
366 return Err(Error::TypeMismatch {
367 expected: cell.type_id,
368 found: declared,
369 sites: vec![ErrorSite::MethodIndex(idx)],
370 });
371 }
372 }
373 }
374
375 let cell_sets: Vec<HashSet<CellId>> = methods
381 .iter()
382 .map(|m| m.inputs.iter().chain(m.outputs.iter()).copied().collect())
383 .collect();
384 if let Some(rel_idx) = cell_sets[1..].iter().position(|set| set != &cell_sets[0]) {
385 let diverging = rel_idx + 1;
386 let mut sites = vec![ErrorSite::MethodIndex(diverging), ErrorSite::MethodIndex(0)];
387 for &c in cell_sets[diverging].symmetric_difference(&cell_sets[0]) {
389 sites.push(ErrorSite::Cell(c));
390 }
391 return Err(Error::MismatchedMethodCells { sites });
392 }
393
394 let mut seen_output_sets: Vec<(usize, HashSet<CellId>, &[CellId])> =
400 Vec::with_capacity(methods.len());
401 for (idx, method) in methods.iter().enumerate() {
402 let output_set: HashSet<CellId> = method.outputs.iter().copied().collect();
403 if output_set.len() != method.outputs.len() {
404 let mut sites = vec![ErrorSite::MethodIndex(idx)];
407 let mut seen = HashSet::new();
408 let mut reported = HashSet::new();
409 for &o in &method.outputs {
410 if !seen.insert(o) && reported.insert(o) {
411 sites.push(ErrorSite::Cell(o));
412 }
413 }
414 return Err(Error::InvalidMethodOutputs { sites });
415 }
416 for (earlier, earlier_set, earlier_outputs) in &seen_output_sets {
417 if output_set == *earlier_set
418 || (output_set.len() < earlier_set.len() && output_set.is_subset(earlier_set))
419 || (earlier_set.len() < output_set.len() && earlier_set.is_subset(&output_set))
420 {
421 let mut sites = vec![
422 ErrorSite::MethodIndex(idx),
423 ErrorSite::MethodIndex(*earlier),
424 ];
425 let offending_outputs: &[CellId] = if output_set.len() <= earlier_set.len() {
426 &method.outputs
427 } else {
428 earlier_outputs
429 };
430 for &o in offending_outputs {
431 sites.push(ErrorSite::Cell(o));
432 }
433 return Err(Error::InvalidMethodOutputs { sites });
434 }
435 }
436 seen_output_sets.push((idx, output_set, &method.outputs));
437 }
438
439 let mut adj: Vec<CellId> = Vec::new();
441 let mut seen: std::collections::HashSet<CellId> = std::collections::HashSet::new();
442 for method in &methods {
443 for &cell_id in method.inputs.iter().chain(method.outputs.iter()) {
444 if seen.insert(cell_id) {
445 adj.push(cell_id);
446 }
447 }
448 }
449
450 self.invalidate_prepared_plans();
451 let rel_id = self.relationships.insert(RelationshipData {
452 methods,
453 adj: adj.clone(),
454 });
455
456 for cell_id in adj {
457 if let Some(cell) = self.cells.get_mut(cell_id)
458 && !cell.adj.contains(&rel_id)
459 {
460 cell.adj.push(rel_id);
461 }
462 }
463
464 self.guard_independent = false;
465 Ok(rel_id)
466 }
467
468 pub fn add_conditional<T: Any + PartialEq + 'static>(
494 &mut self,
495 source: MatchExpr,
496 branches: Vec<(Vec<T>, Vec<RelationshipId>)>,
497 default: Vec<RelationshipId>,
498 ) -> Result<ConditionalId, Error> {
499 match &source.0 {
500 MatchSource::Cell(cell) => {
501 let cell_data = self.cells.get(*cell).ok_or(Error::InvalidId)?;
502 if cell_data.type_id != TypeId::of::<T>() {
503 return Err(Error::InvalidConditional {
504 sites: vec![ErrorSite::Cell(*cell)],
505 });
506 }
507 }
508 MatchSource::Expr(expr) => {
509 if expr.output_type != TypeId::of::<T>() {
510 return Err(Error::InvalidConditional { sites: vec![] });
511 }
512 for (&cell_id, &declared) in expr.inputs.iter().zip(expr.input_types.iter()) {
513 let cell_data = self.cells.get(cell_id).ok_or(Error::InvalidId)?;
514 if cell_data.type_id != declared {
515 return Err(Error::TypeMismatch {
516 expected: cell_data.type_id,
517 found: declared,
518 sites: vec![],
519 });
520 }
521 }
522 }
523 };
524
525 let all_rels: Vec<RelationshipId> = branches
527 .iter()
528 .flat_map(|(_, rels)| rels.iter().copied())
529 .chain(default.iter().copied())
530 .collect();
531
532 for &rel_id in &all_rels {
533 if !self.relationships.contains_key(rel_id) {
534 return Err(Error::InvalidConditional { sites: vec![] });
535 }
536 if self.conditional_relationships.contains(&rel_id) {
537 return Err(Error::InvalidConditional {
538 sites: vec![ErrorSite::Relationship(rel_id)],
539 });
540 }
541 }
542
543 for (keys, _) in &branches {
545 if keys.is_empty() {
546 return Err(Error::InvalidConditional { sites: vec![] });
547 }
548 }
549
550 let mut seen: HashSet<RelationshipId> = HashSet::new();
552 for &rel_id in &all_rels {
553 if !seen.insert(rel_id) {
554 return Err(Error::InvalidConditional {
555 sites: vec![ErrorSite::Relationship(rel_id)],
556 });
557 }
558 }
559
560 let typed_branches: Vec<Branch> = branches
562 .into_iter()
563 .map(|(keys, relationships)| Branch {
564 keys: keys
565 .into_iter()
566 .map(|k| Box::new(k) as Box<dyn Any>)
567 .collect(),
568 relationships,
569 })
570 .collect();
571
572 self.invalidate_prepared_plans();
575 for &rel_id in &all_rels {
576 self.conditional_relationships.insert(rel_id);
577 }
578
579 let id = self.conditionals.insert(ConditionalData {
580 source: source.0,
581 branches: typed_branches,
582 default,
583 });
584
585 self.guard_independent = false;
586 Ok(id)
587 }
588
589 fn cell_has_prior_use(&self, id: CellId) -> bool {
593 self.relationships
594 .values()
595 .any(|rel| rel.methods.iter().any(|m| m.outputs.contains(&id)))
596 }
597
598 pub fn add_requirement(
634 &mut self,
635 cell: CellId,
636 requirement: Requirement,
637 ) -> Result<RequirementId, Error> {
638 self.cells.get(cell).ok_or(Error::InvalidId)?;
639 if requirement.inputs.len() != requirement.input_types.len() {
640 return Err(Error::InvalidRequirement);
641 }
642 for (&input_id, &declared) in requirement
643 .inputs
644 .iter()
645 .zip(requirement.input_types.iter())
646 {
647 let input_cell = self.cells.get(input_id).ok_or(Error::InvalidId)?;
648 if input_cell.type_id != declared {
649 return Err(Error::TypeMismatch {
650 expected: input_cell.type_id,
651 found: declared,
652 sites: vec![],
653 });
654 }
655 }
656
657 if self.cells[cell].kind != CellKind::Out {
658 let inputs: Vec<&dyn Any> = requirement
659 .inputs
660 .iter()
661 .map(|&id| self.cells[id].effective())
662 .collect();
663 let holds = (requirement.function)(&inputs).map_err(|error| Error::MethodFailed {
664 error,
665 sites: vec![],
666 })?;
667 if !holds {
668 return Err(Error::InvalidRequirement);
669 }
670 }
671
672 self.invalidate_prepared_plans();
673 let rid = self.requirements.insert(RequirementData {
674 cell,
675 inputs: requirement.inputs,
676 function: requirement.function,
677 });
678 self.cells[cell].requirements.push(rid);
679 Ok(rid)
680 }
681
682 pub fn add_out(
723 &mut self,
724 writer: Method,
725 requirements: Vec<Requirement>,
726 ) -> Result<CellId, Error> {
727 if writer.outputs.len() != 1 {
728 return Err(Error::InvalidOutput);
729 }
730 let out_cell = writer.outputs[0];
731
732 let kind = self.cells.get(out_cell).ok_or(Error::InvalidId)?.kind;
733 if kind != CellKind::Cell || self.cell_has_prior_use(out_cell) {
734 return Err(Error::InvalidCellKind { sites: vec![] });
735 }
736
737 self.add_relationship(vec![writer])?;
738 self.cells[out_cell].kind = CellKind::Out;
739
740 for requirement in requirements {
741 self.add_requirement(out_cell, requirement)?;
742 }
743
744 Ok(out_cell)
745 }
746
747 pub fn add_filter(&mut self, cell: CellId, filter: Filter) -> Result<(), Error> {
772 let cell_type = self.cells.get(cell).ok_or(Error::InvalidId)?.type_id;
773 if self.cells[cell].filter.is_some() {
774 return Err(Error::InvalidFilter);
775 }
776 if filter.0.value_type != cell_type {
777 return Err(Error::InvalidFilter);
778 }
779 if filter.0.args.contains(&cell) {
780 return Err(Error::InvalidFilter);
781 }
782 for (&arg_id, &declared) in filter.0.args.iter().zip(filter.0.arg_types.iter()) {
783 let arg_cell = self.cells.get(arg_id).ok_or(Error::InvalidId)?;
784 if arg_cell.type_id != declared {
785 return Err(Error::TypeMismatch {
786 expected: arg_cell.type_id,
787 found: declared,
788 sites: vec![],
789 });
790 }
791 }
792
793 self.invalidate_prepared_plans();
794 for &arg in &filter.0.args {
795 self.filter_dependents.entry(arg).or_default().push(cell);
796 }
797 self.cells[cell].filter = Some(filter.0);
798 self.guard_independent = false;
799 Ok(())
800 }
801
802 pub fn filter_args(&self, id: CellId) -> Option<&[CellId]> {
806 self.cells
807 .get(id)?
808 .filter
809 .as_ref()
810 .map(|f| f.args.as_slice())
811 }
812
813 pub fn filter_dependents(&self, id: CellId) -> &[CellId] {
818 self.filter_dependents
819 .get(&id)
820 .map(Vec::as_slice)
821 .unwrap_or(&[])
822 }
823
824 pub fn filter_kind(&self, id: CellId) -> Option<&FilterKind> {
828 self.cells.get(id)?.filter.as_ref().map(|f| &f.kind)
829 }
830
831 pub fn filter_range<T: Any + Clone>(&self, id: CellId) -> Option<(T, T)> {
845 let filter = self.cells.get(id)?.filter.as_ref()?;
846 let FilterKind::Range { bounds } = &filter.kind else {
847 return None;
848 };
849 let args: Vec<&dyn Any> = filter
850 .args
851 .iter()
852 .map(|&a| self.cells[a].effective())
853 .collect();
854 let (lo, hi) = bounds(&args)?;
855 Some((*lo.downcast::<T>().ok()?, *hi.downcast::<T>().ok()?))
856 }
857
858 pub fn filter_violation(&self, id: CellId) -> Option<&FilterViolation> {
865 self.last_filter_violations.get(&id)
866 }
867
868 pub fn filter_violated_cells(&self) -> impl Iterator<Item = CellId> + '_ {
873 self.last_filter_violations.keys().copied()
874 }
875
876 pub fn filter_violation_cells(&self) -> HashSet<CellId> {
886 let mut result = HashSet::new();
887 for cell_id in self.filter_violated_cells() {
888 result.extend(self.contributing_cells(cell_id));
889 if let Some(args) = self.filter_args(cell_id) {
890 for &arg in args {
891 result.extend(self.contributing_cells(arg));
892 }
893 }
894 }
895 result
896 }
897
898 pub fn cell_requirements(&self, id: CellId) -> Option<&[RequirementId]> {
902 self.cells.get(id).map(|c| c.requirements.as_slice())
903 }
904
905 pub fn requirement_cell(&self, id: RequirementId) -> Option<CellId> {
909 self.requirements.get(id).map(|c| c.cell)
910 }
911
912 pub fn requirement_inputs(&self, id: RequirementId) -> Option<&[CellId]> {
916 self.requirements.get(id).map(|c| c.inputs.as_slice())
917 }
918
919 pub fn cell_requirements_valid(&self, id: CellId) -> bool {
926 if self.last_plan.is_none() {
927 return false;
928 }
929 !self.last_requirement_violations.contains_key(&id)
930 }
931
932 pub fn violated_requirements(&self, id: CellId) -> impl Iterator<Item = RequirementId> + '_ {
938 self.last_requirement_violations
939 .get(&id)
940 .into_iter()
941 .flatten()
942 .copied()
943 }
944
945 pub fn contributing_cells(&self, id: CellId) -> HashSet<CellId> {
977 let mut result = HashSet::new();
978 let mut visited: HashSet<CellId> = HashSet::new();
979 let mut stack = vec![id];
980 while let Some(current) = stack.pop() {
981 if !visited.insert(current) {
982 continue;
983 }
984
985 for match_cell in self.conditionals_potentially_producing(current) {
986 stack.push(match_cell);
987 }
988
989 if !self.is_forced(current) {
990 result.insert(current);
991 }
992
993 let Some(adj) = self.cells.get(current).map(|c| c.adj.clone()) else {
994 continue;
995 };
996 for rel_id in adj {
997 if !self.is_relationship_active(rel_id) {
998 continue;
999 }
1000 for method in &self.relationships[rel_id].methods {
1001 if !method.outputs.contains(¤t) {
1002 continue;
1003 }
1004 for &input in &method.inputs {
1005 if method.outputs.contains(&input) {
1006 result.insert(input);
1007 } else {
1008 stack.push(input);
1009 }
1010 }
1011 }
1012 }
1013 }
1014 result
1015 }
1016
1017 fn is_relationship_active(&self, rel_id: RelationshipId) -> bool {
1024 self.last_plan
1025 .as_ref()
1026 .is_some_and(|plan| plan.active.contains(&rel_id))
1027 }
1028
1029 fn conditionals_potentially_producing(&self, cell: CellId) -> Vec<CellId> {
1037 self.conditionals
1038 .values()
1039 .filter(|cond| {
1040 cond.branches
1041 .iter()
1042 .flat_map(|branch| branch.relationships.iter())
1043 .chain(cond.default.iter())
1044 .any(|&rel_id| self.relationships[rel_id].adj.contains(&cell))
1045 })
1046 .flat_map(|cond| cond.match_cells().iter().copied())
1047 .collect()
1048 }
1049
1050 pub fn requirement_contributing_cells(&self, id: RequirementId) -> HashSet<CellId> {
1058 let Some(requirement) = self.requirements.get(id) else {
1059 return HashSet::new();
1060 };
1061 requirement
1062 .inputs
1063 .iter()
1064 .flat_map(|&input| self.contributing_cells(input))
1065 .collect()
1066 }
1067
1068 pub fn requirement_relevant_cells(&self) -> HashSet<CellId> {
1076 self.cells
1077 .iter()
1078 .filter(|(_, c)| !c.requirements.is_empty())
1079 .flat_map(|(id, _)| self.contributing_cells(id))
1080 .collect()
1081 }
1082
1083 pub fn requirement_violation_cells(&self) -> HashSet<CellId> {
1092 self.cells
1093 .keys()
1094 .flat_map(|id| self.violated_requirements(id))
1095 .flat_map(|rid| self.requirement_contributing_cells(rid))
1096 .collect()
1097 }
1098
1099 pub fn write<T: Any + 'static>(&mut self, id: CellId, value: T) -> Result<(), Error> {
1116 if self.cells.get(id).is_some_and(|c| c.kind == CellKind::Out) {
1117 return Err(Error::InvalidCellKind { sites: vec![] });
1118 }
1119 let cell_type = self.cells.get(id).ok_or(Error::InvalidId)?.type_id;
1120 if cell_type != TypeId::of::<T>() {
1121 return Err(Error::TypeMismatch {
1122 expected: cell_type,
1123 found: TypeId::of::<T>(),
1124 sites: vec![],
1125 });
1126 }
1127
1128 self.invalidate_after_write(id);
1129 self.next_strength += 1;
1130 let cell = &mut self.cells[id];
1131 cell.strength = self.next_strength | (1u64 << 63);
1132 cell.source = Box::new(value);
1133 cell.derived = None;
1134 Ok(())
1135 }
1136
1137 pub fn read<T: Any + 'static>(&self, id: CellId) -> Result<&T, Error> {
1145 let cell = self.cells.get(id).ok_or(Error::InvalidId)?;
1146 if cell.type_id != TypeId::of::<T>() {
1147 return Err(Error::TypeMismatch {
1148 expected: cell.type_id,
1149 found: TypeId::of::<T>(),
1150 sites: vec![],
1151 });
1152 }
1153 Ok(cell
1154 .effective()
1155 .downcast_ref::<T>()
1156 .expect("type checked above"))
1157 }
1158
1159 pub fn source<T: Any + 'static>(&self, id: CellId) -> Result<&T, Error> {
1181 let cell = self.cells.get(id).ok_or(Error::InvalidId)?;
1182 if cell.type_id != TypeId::of::<T>() {
1183 return Err(Error::TypeMismatch {
1184 expected: cell.type_id,
1185 found: TypeId::of::<T>(),
1186 sites: vec![],
1187 });
1188 }
1189 Ok(cell.source.downcast_ref::<T>().expect("type checked above"))
1190 }
1191
1192 pub fn changed(&self) -> impl Iterator<Item = CellId> + '_ {
1204 self.changed_cells.iter().copied()
1205 }
1206
1207 pub fn clear_changed(&mut self) {
1213 for id in std::mem::take(&mut self.changed_cells) {
1214 if let Some(cell) = self.cells.get_mut(id) {
1215 cell.changed = false;
1216 }
1217 }
1218 }
1219
1220 pub fn validate(&mut self) -> Result<(), Error> {
1255 if self.guard_independent {
1256 return Ok(());
1257 }
1258 if let Some(path) = self.guard_violation() {
1259 return Err(Error::DependencyCycle {
1260 sites: path.into_sites(),
1261 });
1262 }
1263 self.guard_independent = true;
1264 Ok(())
1265 }
1266
1267 pub fn cells(&self) -> impl Iterator<Item = CellId> + '_ {
1271 self.cells.keys()
1272 }
1273
1274 pub fn relationships(&self) -> impl Iterator<Item = RelationshipId> + '_ {
1278 self.relationships.keys()
1279 }
1280
1281 pub fn cell_adj(&self, id: CellId) -> Option<&[RelationshipId]> {
1287 self.cells.get(id).map(|c| c.adj.as_slice())
1288 }
1289
1290 pub fn relationship_adj(&self, id: RelationshipId) -> Option<&[CellId]> {
1296 self.relationships.get(id).map(|r| r.adj.as_slice())
1297 }
1298
1299 fn evaluate_match_source(&self, cond: &ConditionalData) -> Result<MatchValue<'_>, Error> {
1306 match &cond.source {
1307 MatchSource::Cell(id) => Ok(MatchValue::Ref(self.cells[*id].effective())),
1308 MatchSource::Expr(expr) => {
1309 let args: Vec<&dyn Any> = expr
1310 .inputs
1311 .iter()
1312 .map(|&id| self.cells[id].effective())
1313 .collect();
1314 let value = (expr.function)(&args).map_err(|error| Error::MethodFailed {
1315 error,
1316 sites: vec![],
1317 })?;
1318 Ok(MatchValue::Owned(value))
1319 }
1320 }
1321 }
1322
1323 fn evaluate_match_source_staged<'a>(
1334 &'a self,
1335 cond: &ConditionalData,
1336 stage: &'a PropagationStage,
1337 ) -> Result<MatchValue<'a>, Error> {
1338 match &cond.source {
1339 MatchSource::Cell(id) => Ok(MatchValue::Ref(stage.effective(&self.cells, *id))),
1340 MatchSource::Expr(expr) => {
1341 let args: Vec<&dyn Any> = expr
1342 .inputs
1343 .iter()
1344 .map(|&id| stage.effective(&self.cells, id))
1345 .collect();
1346 let value = (expr.function)(&args).map_err(|error| Error::MethodFailed {
1347 error,
1348 sites: vec![],
1349 })?;
1350 Ok(MatchValue::Owned(value))
1351 }
1352 }
1353 }
1354
1355 fn match_eq_fn(&self, cond: &ConditionalData) -> fn(&dyn Any, &dyn Any) -> bool {
1359 match &cond.source {
1360 MatchSource::Cell(id) => self.cells[*id].eq_fn,
1361 MatchSource::Expr(expr) => expr.eq_fn,
1362 }
1363 }
1364
1365 fn build_active_set_staged(
1376 &self,
1377 stage: &PropagationStage,
1378 ) -> Result<HashSet<RelationshipId>, Error> {
1379 let mut active: HashSet<RelationshipId> = self
1380 .relationships
1381 .keys()
1382 .filter(|id| !self.conditional_relationships.contains(id))
1383 .collect();
1384
1385 for (_, cond) in &self.conditionals {
1386 let value = self.evaluate_match_source_staged(cond, stage)?;
1387 let value_ref = value.as_dyn();
1388 let eq_fn = self.match_eq_fn(cond);
1389
1390 let mut matched = false;
1391 for branch in &cond.branches {
1392 if branch.keys.iter().any(|key| eq_fn(value_ref, key.as_ref())) {
1393 for &rel_id in &branch.relationships {
1394 active.insert(rel_id);
1395 }
1396 matched = true;
1397 break;
1398 }
1399 }
1400 if !matched {
1401 for &rel_id in &cond.default {
1402 active.insert(rel_id);
1403 }
1404 }
1405 }
1406
1407 Ok(active)
1408 }
1409
1410 fn plan_provenance(&self, plan: &Plan) -> PlanProvenance {
1415 let mut provenance = PlanProvenance::default();
1416 let mut effective_producers = HashMap::new();
1417 let mut source_producers = HashMap::new();
1418
1419 for &step in &plan.execution_order {
1420 let step_provenance = match step {
1421 PlanStep::Method(rel_id, method_index) => {
1422 let method = &self.relationships[rel_id].methods[method_index];
1423 let method_inputs: HashSet<CellId> = method.inputs.iter().copied().collect();
1424 let method_outputs: HashSet<CellId> = method.outputs.iter().copied().collect();
1425 let mut input_producers = Vec::with_capacity(method.inputs.len());
1426 let mut seed_inputs = Vec::new();
1427 for &input in &method.inputs {
1428 if method_outputs.contains(&input) {
1429 seed_inputs.push(input);
1430 input_producers.push(None);
1431 } else {
1432 input_producers.push(effective_producers.get(&input).copied());
1433 }
1434 }
1435 let output_classes: Vec<_> = method
1436 .outputs
1437 .iter()
1438 .map(|&output| {
1439 (
1440 output,
1441 if method_inputs.contains(&output)
1442 || plan.forced_outputs.contains(&output)
1443 {
1444 OutputClassification::Derived
1445 } else {
1446 OutputClassification::Source
1447 },
1448 )
1449 })
1450 .collect();
1451 let step_provenance = StepProvenance {
1452 input_producers,
1453 seed_inputs,
1454 source_producer: None,
1455 output_classes: output_classes.clone(),
1456 };
1457 for &(output, _) in &output_classes {
1458 effective_producers.insert(output, step);
1459 }
1460 for &(output, classification) in &output_classes {
1461 if classification == OutputClassification::Source {
1462 source_producers.insert(output, step);
1463 }
1464 }
1465 step_provenance
1466 }
1467 PlanStep::FilterReclamp(cell) => {
1468 let filter = self.cells[cell]
1469 .filter
1470 .as_ref()
1471 .expect("plan() only emits FilterReclamp for a filtered cell");
1472 let input_producers = filter
1473 .args
1474 .iter()
1475 .map(|input| effective_producers.get(input).copied())
1476 .collect();
1477 let step_provenance = StepProvenance {
1478 input_producers,
1479 seed_inputs: Vec::new(),
1480 source_producer: source_producers.get(&cell).copied(),
1481 output_classes: vec![(cell, OutputClassification::Derived)],
1482 };
1483 effective_producers.insert(cell, step);
1484 step_provenance
1485 }
1486 };
1487 provenance.steps.insert(step, step_provenance);
1488 }
1489 provenance.output_producers = effective_producers;
1490 provenance
1491 }
1492
1493 fn prerequisite_step_is_compatible(
1498 &self,
1499 pre_plan: &PlanProvenance,
1500 final_plan: &PlanProvenance,
1501 step: PlanStep,
1502 stage: &PropagationStage,
1503 ) -> bool {
1504 let Some(staged) = stage.step_provenance.get(&step) else {
1505 return false;
1506 };
1507 pre_plan.steps.get(&step) == Some(staged) && final_plan.steps.get(&step) == Some(staged)
1508 }
1509
1510 fn conflict_sites_for_step(
1514 &self,
1515 step: PlanStep,
1516 pre_plan: &PlanProvenance,
1517 final_plan: &PlanProvenance,
1518 ) -> Vec<ErrorSite> {
1519 let mut sites = Vec::new();
1520 let mut seen_sites = HashSet::new();
1521 let mut add_site = |site| {
1522 if seen_sites.insert(site) {
1523 sites.push(site);
1524 }
1525 };
1526 let mut cells = Vec::new();
1527
1528 match step {
1529 PlanStep::Method(rel_id, method_index) => {
1530 add_site(ErrorSite::Relationship(rel_id));
1531 add_site(ErrorSite::Method(rel_id, method_index));
1532 let method = &self.relationships[rel_id].methods[method_index];
1533 cells.extend(method.inputs.iter().copied());
1534 cells.extend(method.outputs.iter().copied());
1535 }
1536 PlanStep::FilterReclamp(cell) => {
1537 cells.push(cell);
1538 if let Some(filter) = &self.cells[cell].filter {
1539 cells.extend(filter.args.iter().copied());
1540 }
1541 }
1542 }
1543
1544 for provenance in [pre_plan.steps.get(&step), final_plan.steps.get(&step)]
1545 .into_iter()
1546 .flatten()
1547 {
1548 for producer in provenance
1549 .input_producers
1550 .iter()
1551 .copied()
1552 .flatten()
1553 .chain(provenance.source_producer)
1554 {
1555 Self::add_step_relationship_site(producer, &mut add_site);
1556 }
1557 }
1558 for cell in cells {
1559 add_site(ErrorSite::Cell(cell));
1560 for plan in [pre_plan, final_plan] {
1561 if let Some(&producer) = plan.output_producers.get(&cell) {
1562 Self::add_step_relationship_site(producer, &mut add_site);
1563 }
1564 }
1565 }
1566 sites
1567 }
1568
1569 fn add_step_relationship_site(step: PlanStep, add_site: &mut impl FnMut(ErrorSite)) {
1571 match step {
1572 PlanStep::Method(rel_id, _) => add_site(ErrorSite::Relationship(rel_id)),
1573 PlanStep::FilterReclamp(cell) => add_site(ErrorSite::Cell(cell)),
1574 }
1575 }
1576
1577 fn execute_plan_staged(
1592 &self,
1593 execution_order: &[PlanStep],
1594 seeds: &Seeds,
1595 forced_outputs: &HashSet<CellId>,
1596 plan_provenance: &PlanProvenance,
1597 stage: &mut PropagationStage,
1598 filter_violations: &mut Vec<(CellId, FilterViolation)>,
1599 ) -> Result<(), Error> {
1600 for step in execution_order {
1601 match *step {
1602 PlanStep::Method(rel_id, method_idx) => {
1603 if stage.executed_methods.contains(&(rel_id, method_idx)) {
1604 let method = &self.relationships[rel_id].methods[method_idx];
1605 for &output in &method.outputs {
1606 stage.reclassify(
1607 output,
1608 method.inputs.contains(&output) || forced_outputs.contains(&output),
1609 );
1610 }
1611 continue;
1612 }
1613 let (outputs, output_ids, shadow_outputs) = {
1614 let method = &self.relationships[rel_id].methods[method_idx];
1615 let inputs: Vec<&dyn Any> = method
1616 .inputs
1617 .iter()
1618 .map(|&id| {
1619 if method.outputs.contains(&id) {
1620 seeds
1621 .get(&id)
1622 .map(|value| value.as_ref())
1623 .unwrap_or_else(|| stage.source(&self.cells, id))
1624 } else {
1625 stage.effective(&self.cells, id)
1626 }
1627 })
1628 .collect();
1629 let outputs =
1630 (method.function)(&inputs).map_err(|error| Error::MethodFailed {
1631 error,
1632 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1633 })?;
1634 let output_ids = method.outputs.clone();
1635 let shadow_outputs: Vec<bool> = method
1636 .outputs
1637 .iter()
1638 .map(|o| method.inputs.contains(o) || forced_outputs.contains(o))
1639 .collect();
1640 (outputs, output_ids, shadow_outputs)
1641 };
1642
1643 if outputs.len() != output_ids.len() {
1644 return Err(Error::MethodFailed {
1645 error: anyhow::anyhow!(
1646 "method produced {} outputs but relationship expects {}",
1647 outputs.len(),
1648 output_ids.len()
1649 ),
1650 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1651 });
1652 }
1653
1654 for ((cell_id, new_value), shadow) in
1655 output_ids.into_iter().zip(outputs).zip(shadow_outputs)
1656 {
1657 let found = new_value.as_ref().type_id();
1658 let cell = &self.cells[cell_id];
1659 if found != cell.type_id {
1660 return Err(Error::TypeMismatch {
1661 expected: cell.type_id,
1662 found,
1663 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1664 });
1665 }
1666 stage.write(cell_id, new_value, shadow);
1667 }
1668 stage.executed_methods.insert((rel_id, method_idx));
1669 stage
1670 .step_provenance
1671 .insert(*step, plan_provenance.steps[step].clone());
1672 }
1673 PlanStep::FilterReclamp(id) => {
1674 if stage.executed_filters.contains(&id) {
1675 continue;
1676 }
1677 let filter = self.cells[id]
1678 .filter
1679 .as_ref()
1680 .expect("plan() only emits FilterReclamp for a filtered cell");
1681 let args: Vec<&dyn Any> = filter
1682 .args
1683 .iter()
1684 .map(|&a| stage.effective(&self.cells, a))
1685 .collect();
1686 let current = stage.source(&self.cells, id);
1687 match (filter.function)(current, &args) {
1688 Ok(v) if v.as_ref().type_id() == self.cells[id].type_id => {
1689 stage.write(id, v, true);
1690 }
1691 Ok(_) => filter_violations.push((
1692 id,
1693 FilterViolation::Failed(anyhow::anyhow!(
1694 "filter returned a value of a different type than the cell"
1695 )),
1696 )),
1697 Err(error) => {
1698 filter_violations.push((id, FilterViolation::Failed(error)));
1699 }
1700 }
1701 stage.executed_filters.insert(id);
1702 stage
1703 .step_provenance
1704 .insert(*step, plan_provenance.steps[step].clone());
1705 }
1706 }
1707 }
1708 Ok(())
1709 }
1710
1711 fn post_process_strengths(&mut self, execution_order: &[PlanStep]) -> bool {
1730 let mut changed = false;
1731 let mut derived_strength = u64::MAX >> 1; let mut seen: std::collections::HashSet<CellId> = std::collections::HashSet::new();
1733 for step in execution_order {
1734 let PlanStep::Method(rel_id, method_idx) = step else {
1735 continue;
1736 };
1737 if let Some(rel) = self.relationships.get(*rel_id)
1738 && let Some(method) = rel.methods.get(*method_idx)
1739 {
1740 for &output in &method.outputs {
1741 let self_referencing = method.inputs.contains(&output);
1742 if seen.insert(output)
1743 && let Some(cell) = self.cells.get_mut(output)
1744 {
1745 if self_referencing && cell.has_explicit_strength() {
1746 continue;
1747 }
1748 changed |= cell.strength != derived_strength;
1749 cell.strength = derived_strength;
1750 derived_strength = derived_strength.saturating_sub(1);
1751 }
1752 }
1753 }
1754 }
1755 changed
1756 }
1757
1758 fn commit_stage(&mut self, stage: PropagationStage) -> Vec<CellId> {
1765 let previously_derived: Vec<CellId> = self
1766 .cells
1767 .iter()
1768 .filter(|(_, cell)| cell.derived.is_some())
1769 .map(|(id, _)| id)
1770 .collect();
1771 for (_, cell) in self.cells.iter_mut() {
1772 cell.derived = None;
1773 }
1774 for (id, value) in stage.sources {
1775 self.cells[id].source = value;
1776 }
1777 for (id, value) in stage.derived {
1778 self.cells[id].derived = Some(value);
1779 }
1780 for id in stage.changed {
1781 let cell = &mut self.cells[id];
1782 if !cell.changed {
1783 cell.changed = true;
1784 self.changed_cells.push(id);
1785 }
1786 }
1787 previously_derived
1788 }
1789
1790 pub fn propagate(&mut self) -> Result<(), Error> {
1886 let mut pre = self.pre_plan_cache.take();
1887 let mut main = self.main_plan_cache.take();
1888 let result = self.propagate_with_caches(&mut pre, &mut main);
1889 if result.is_ok() {
1890 self.pre_plan_cache = pre;
1891 self.main_plan_cache = main;
1892 }
1893 result
1894 }
1895
1896 #[cfg(test)]
1927 fn execute_plan(
1928 &mut self,
1929 execution_order: &[PlanStep],
1930 seeds: &Seeds,
1931 forced_outputs: &HashSet<CellId>,
1932 filter_violations: &mut Vec<(CellId, FilterViolation)>,
1933 ) -> Result<(), Error> {
1934 for step in execution_order {
1935 match *step {
1936 PlanStep::Method(rel_id, method_idx) => {
1937 let (outputs, output_ids, shadow_outputs) = {
1938 let method = &self.relationships[rel_id].methods[method_idx];
1939 let inputs: Vec<&dyn Any> = method
1940 .inputs
1941 .iter()
1942 .map(|&id| {
1943 if method.outputs.contains(&id) {
1944 seeds
1948 .get(&id)
1949 .map(|value| value.as_ref())
1950 .unwrap_or_else(|| self.cells[id].source.as_ref())
1951 } else {
1952 self.cells[id].effective()
1953 }
1954 })
1955 .collect();
1956 let outputs =
1957 (method.function)(&inputs).map_err(|error| Error::MethodFailed {
1958 error,
1959 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1960 })?;
1961 let output_ids = method.outputs.clone();
1962 let shadow_outputs: Vec<bool> = method
1963 .outputs
1964 .iter()
1965 .map(|o| method.inputs.contains(o) || forced_outputs.contains(o))
1966 .collect();
1967 (outputs, output_ids, shadow_outputs)
1968 };
1969
1970 if outputs.len() != output_ids.len() {
1971 return Err(Error::MethodFailed {
1972 error: anyhow::anyhow!(
1973 "method produced {} outputs but relationship expects {}",
1974 outputs.len(),
1975 output_ids.len()
1976 ),
1977 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1978 });
1979 }
1980
1981 for ((cell_id, new_value), shadow) in
1982 output_ids.into_iter().zip(outputs).zip(shadow_outputs)
1983 {
1984 let cell = &mut self.cells[cell_id];
1985 let found = new_value.as_ref().type_id();
1986 if found != cell.type_id {
1987 return Err(Error::TypeMismatch {
1988 expected: cell.type_id,
1989 found,
1990 sites: vec![ErrorSite::Method(rel_id, method_idx)],
1991 });
1992 }
1993 if shadow {
1994 cell.derived = Some(new_value);
1995 } else {
1996 cell.source = new_value;
1997 cell.derived = None;
1998 }
1999 if !cell.changed {
2000 cell.changed = true;
2001 self.changed_cells.push(cell_id);
2002 }
2003 }
2004 }
2005 PlanStep::FilterReclamp(id) => {
2006 let filter = self.cells[id]
2007 .filter
2008 .as_ref()
2009 .expect("plan() only emits FilterReclamp for a filtered cell");
2010 let args: Vec<&dyn Any> = filter
2011 .args
2012 .iter()
2013 .map(|&a| self.cells[a].effective())
2014 .collect();
2015 let current = self.cells[id].source.as_ref();
2021 match (filter.function)(current, &args) {
2022 Ok(v) => {
2023 let cell_type = self.cells[id].type_id;
2024 if v.as_ref().type_id() != cell_type {
2025 filter_violations.push((
2026 id,
2027 FilterViolation::Failed(anyhow::anyhow!(
2028 "filter returned a value of a different type than \
2029 the cell"
2030 )),
2031 ));
2032 } else {
2033 let cell = &mut self.cells[id];
2038 cell.derived = Some(v);
2039 if !cell.changed {
2040 cell.changed = true;
2041 self.changed_cells.push(id);
2042 }
2043 }
2044 }
2045 Err(e) => filter_violations.push((id, FilterViolation::Failed(e))),
2046 }
2047 }
2048 }
2049 }
2050 Ok(())
2051 }
2052
2053 pub fn selected_method(&self, rel: RelationshipId) -> Option<usize> {
2058 self.last_plan
2059 .as_ref()?
2060 .plan
2061 .execution_order
2062 .iter()
2063 .find_map(|step| match step {
2064 PlanStep::Method(r, idx) if *r == rel => Some(*idx),
2065 _ => None,
2066 })
2067 }
2068
2069 pub fn method_inputs(&self, rel: RelationshipId, idx: usize) -> Option<&[CellId]> {
2073 self.relationships
2074 .get(rel)?
2075 .methods
2076 .get(idx)
2077 .map(|m| m.inputs.as_slice())
2078 }
2079
2080 pub fn method_outputs(&self, rel: RelationshipId, idx: usize) -> Option<&[CellId]> {
2084 self.relationships
2085 .get(rel)?
2086 .methods
2087 .get(idx)
2088 .map(|m| m.outputs.as_slice())
2089 }
2090
2091 pub fn is_source(&self, id: CellId) -> bool {
2100 let Some(plan) = &self.last_plan else {
2101 return false;
2102 };
2103 !plan.certificate.contains_cell(id) || plan.certificate.is_released(id)
2104 }
2105
2106 pub fn is_forced(&self, id: CellId) -> bool {
2115 self.last_plan
2116 .as_ref()
2117 .is_some_and(|prepared| prepared.plan.forced_outputs.contains(&id))
2118 }
2119
2120 pub fn forced_cells(&self) -> impl Iterator<Item = CellId> + '_ {
2125 self.last_plan
2126 .iter()
2127 .flat_map(|prepared| prepared.plan.forced_outputs.iter().copied())
2128 }
2129
2130 pub fn is_relationship_forced(&self, id: RelationshipId) -> bool {
2136 self.last_plan
2137 .as_ref()
2138 .is_some_and(|prepared| prepared.plan.forced_relationships.contains(&id))
2139 }
2140
2141 pub fn forced_relationships(&self) -> impl Iterator<Item = RelationshipId> + '_ {
2146 self.last_plan
2147 .iter()
2148 .flat_map(|prepared| prepared.plan.forced_relationships.iter().copied())
2149 }
2150
2151 pub fn conditionals(&self) -> impl Iterator<Item = ConditionalId> + '_ {
2155 self.conditionals.keys()
2156 }
2157
2158 pub fn out_cells(&self) -> impl Iterator<Item = CellId> + '_ {
2162 self.cells
2163 .iter()
2164 .filter(|(_, c)| c.kind == CellKind::Out)
2165 .map(|(id, _)| id)
2166 }
2167
2168 pub fn conditional_match_cells(&self, id: ConditionalId) -> Option<&[CellId]> {
2173 self.conditionals.get(id).map(|c| c.match_cells())
2174 }
2175
2176 pub fn conditional_branch_count(&self, id: ConditionalId) -> Option<usize> {
2180 self.conditionals.get(id).map(|c| c.branches.len())
2181 }
2182
2183 pub fn conditional_branch_relationships(
2187 &self,
2188 id: ConditionalId,
2189 branch: usize,
2190 ) -> Option<&[RelationshipId]> {
2191 self.conditionals
2192 .get(id)?
2193 .branches
2194 .get(branch)
2195 .map(|b| b.relationships.as_slice())
2196 }
2197
2198 pub fn conditional_default_relationships(
2203 &self,
2204 id: ConditionalId,
2205 ) -> Option<&[RelationshipId]> {
2206 self.conditionals.get(id).map(|c| c.default.as_slice())
2207 }
2208
2209 pub fn conditional_active_branch(&self, id: ConditionalId) -> Result<Option<usize>, Error> {
2223 let Some(cond) = self.conditionals.get(id) else {
2224 return Ok(None);
2225 };
2226 let value = self.evaluate_match_source(cond)?;
2227 let value_ref = value.as_dyn();
2228 let eq_fn = self.match_eq_fn(cond);
2229 Ok(cond
2230 .branches
2231 .iter()
2232 .enumerate()
2233 .find(|(_, branch)| branch.keys.iter().any(|key| eq_fn(value_ref, key.as_ref())))
2234 .map(|(i, _)| i))
2235 }
2236}
2237
2238impl Default for Sheet {
2239 fn default() -> Self {
2241 Self::new()
2242 }
2243}
2244
2245#[cfg(test)]
2246mod tests {
2247 use crate::{
2248 CellKind, ConditionalId, Error, MatchExpr, Method, Requirement, Sheet,
2249 cell::CellId,
2250 error::ErrorSite,
2251 filter::{Filter, FilterKind, FilterViolation},
2252 planner::{PlanStep, Seeds},
2253 relationship::RelationshipId,
2254 };
2255 use std::any::{Any, TypeId};
2256 use std::collections::{HashMap, HashSet};
2257
2258 #[test]
2259 fn add_cell_has_cell_kind() {
2260 let mut sheet = Sheet::new();
2261 let a = sheet.add_cell(0_i32);
2262 assert_eq!(sheet.cell_kind(a), Some(CellKind::Cell));
2263 }
2264
2265 #[test]
2266 fn add_source_has_source_kind() {
2267 let mut sheet = Sheet::new();
2268 let a = sheet.add_source(0_i32);
2269 assert_eq!(sheet.cell_kind(a), Some(CellKind::Source));
2270 }
2271
2272 #[test]
2273 fn cell_kind_returns_none_for_invalid_id() {
2274 let mut sheet = Sheet::new();
2275 sheet.add_cell(0_i32); let mut other = Sheet::new();
2277 other.add_cell(0_i32); let bogus = other.add_cell(0_i32); assert_eq!(sheet.cell_kind(bogus), None);
2284 }
2285
2286 #[test]
2287 fn execute_plan_clears_a_stale_derived_override_on_a_later_plain_write() {
2288 let mut sheet = Sheet::new();
2295 let x = sheet.add_cell(1_i32);
2296 let y = sheet.add_cell(2_i32);
2297 let z = sheet.add_cell(10_i32);
2298 let self_ref = sheet
2299 .add_relationship(vec![
2300 Method::from_fn_2_1([x, y], x, |a: &i32, b: &i32| Ok((*a).min(*b))),
2301 Method::from_fn_2_1([x, y], y, |a: &i32, b: &i32| Ok((*a).max(*b))),
2302 ])
2303 .unwrap();
2304 let plain = sheet
2305 .add_relationship(vec![Method::from_fn_1_1(z, x, |v: &i32| Ok(*v + 1))])
2306 .unwrap();
2307
2308 let no_seeds: Seeds = HashMap::new();
2309 let no_forced: HashSet<CellId> = HashSet::new();
2310 sheet
2311 .execute_plan(
2312 &[PlanStep::Method(self_ref, 0)],
2313 &no_seeds,
2314 &no_forced,
2315 &mut Vec::new(),
2316 )
2317 .unwrap();
2318 assert_eq!(*sheet.read::<i32>(x).unwrap(), 1);
2319
2320 sheet.write(z, 41_i32).unwrap();
2321 sheet
2322 .execute_plan(
2323 &[PlanStep::Method(plain, 0)],
2324 &no_seeds,
2325 &no_forced,
2326 &mut Vec::new(),
2327 )
2328 .unwrap();
2329
2330 assert_eq!(*sheet.read::<i32>(x).unwrap(), 42);
2331 }
2332
2333 #[test]
2334 fn add_conditional_returns_error_for_invalid_cell() {
2335 let mut sheet = Sheet::new();
2336 let result = sheet.add_conditional(
2337 MatchExpr::cell(CellId::default()),
2338 vec![(vec![0_i32], vec![])],
2339 vec![],
2340 );
2341 assert!(matches!(result, Err(Error::InvalidId)));
2342 }
2343
2344 #[test]
2345 fn add_conditional_returns_invalid_conditional_for_type_mismatch() {
2346 let mut sheet = Sheet::new();
2347 let a = sheet.add_cell(0_i32);
2348 let result =
2350 sheet.add_conditional(MatchExpr::cell(a), vec![(vec![0.0_f64], vec![])], vec![]);
2351 assert!(matches!(result, Err(Error::InvalidConditional { .. })));
2352 }
2353
2354 #[test]
2355 fn add_conditional_returns_invalid_conditional_for_missing_relationship() {
2356 let mut sheet = Sheet::new();
2357 let a = sheet.add_cell(0_i32);
2358 let result = sheet.add_conditional(
2359 MatchExpr::cell(a),
2360 vec![(vec![0_i32], vec![RelationshipId::default()])],
2361 vec![],
2362 );
2363 assert!(matches!(result, Err(Error::InvalidConditional { .. })));
2364 }
2365
2366 #[test]
2367 fn validate_returns_dependency_cycle_for_multi_method_relationship_involving_match_cell() {
2368 let mut sheet = Sheet::new();
2369 let a = sheet.add_cell(0_i32);
2370 let b = sheet.add_cell(0_i32);
2371 let rel = sheet
2373 .add_relationship(vec![
2374 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
2375 Method::from_fn_1_1(b, a, |x: &i32| Ok(*x)),
2376 ])
2377 .unwrap();
2378 sheet
2379 .add_conditional(MatchExpr::cell(a), vec![(vec![0_i32], vec![rel])], vec![])
2380 .unwrap();
2381 assert!(matches!(
2382 sheet.validate(),
2383 Err(Error::DependencyCycle { .. })
2384 ));
2385 }
2386
2387 #[test]
2388 fn dependency_cycle_from_a_conditional_names_the_match_cell() {
2389 let mut sheet = Sheet::new();
2390 let a = sheet.add_cell(0_i32);
2391 let b = sheet.add_cell(0_i32);
2392 let rel = sheet
2394 .add_relationship(vec![
2395 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
2396 Method::from_fn_1_1(b, a, |x: &i32| Ok(*x)),
2397 ])
2398 .unwrap();
2399 sheet
2400 .add_conditional(MatchExpr::cell(a), vec![(vec![0_i32], vec![rel])], vec![])
2401 .unwrap();
2402 let err = sheet.validate().unwrap_err();
2403 assert!(err.sites().contains(&ErrorSite::Cell(a)));
2404 }
2405
2406 #[test]
2407 fn add_conditional_returns_error_when_branch_rel_writes_a_cell_upstream_of_match_cell() {
2408 let mut sheet = Sheet::new();
2409 let a = sheet.add_cell(0_i32);
2410 let b = sheet.add_cell(0_i32);
2411 let p = sheet.add_cell(0_i32);
2412 sheet
2414 .add_relationship(vec![Method::from_fn_1_1(a, p, |x: &i32| Ok(*x))])
2415 .unwrap();
2416 let rel = sheet
2418 .add_relationship(vec![
2419 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
2420 Method::from_fn_1_1(b, a, |x: &i32| Ok(*x)),
2421 ])
2422 .unwrap();
2423 sheet
2424 .add_conditional(MatchExpr::cell(p), vec![(vec![0_i32], vec![rel])], vec![])
2425 .unwrap();
2426 assert!(matches!(
2427 sheet.validate(),
2428 Err(Error::DependencyCycle { .. })
2429 ));
2430 }
2431
2432 #[test]
2433 fn add_conditional_returns_error_when_branch_rel_writes_a_cell_upstream_of_either_expr_input() {
2434 let mut sheet = Sheet::new();
2435 let a = sheet.add_cell(0_i32);
2436 let b = sheet.add_cell(0_i32);
2437 let p = sheet.add_cell(0_i32);
2438 let q = sheet.add_cell(0_i32);
2439 sheet
2441 .add_relationship(vec![Method::from_fn_1_1(a, q, |x: &i32| Ok(*x))])
2442 .unwrap();
2443 let rel = sheet
2446 .add_relationship(vec![
2447 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
2448 Method::from_fn_1_1(b, a, |x: &i32| Ok(*x)),
2449 ])
2450 .unwrap();
2451 let expr = MatchExpr::from_fn_2([p, q], |x: &i32, y: &i32| Ok(*x + *y));
2452 sheet
2453 .add_conditional(expr, vec![(vec![0_i32], vec![rel])], vec![])
2454 .unwrap();
2455 assert!(matches!(
2456 sheet.validate(),
2457 Err(Error::DependencyCycle { .. })
2458 ));
2459 }
2460
2461 #[test]
2462 fn add_conditional_activates_branch_from_two_cell_expression() {
2463 let mut sheet = Sheet::new();
2464 let a = sheet.add_cell(false);
2465 let b = sheet.add_cell(false);
2466 let x = sheet.add_cell(0_i32);
2467 let y = sheet.add_cell(0_i32);
2468 let rel_true = sheet
2469 .add_relationship(vec![Method::from_fn_1_1(x, y, |v: &i32| Ok(*v))])
2470 .unwrap();
2471 let expr = MatchExpr::from_fn_2([a, b], |p: &bool, q: &bool| Ok(*p && *q));
2472 let cid = sheet
2473 .add_conditional(expr, vec![(vec![true], vec![rel_true])], vec![])
2474 .unwrap();
2475
2476 sheet.write(a, true).unwrap();
2477 sheet.write(b, false).unwrap();
2478 assert_eq!(sheet.conditional_active_branch(cid).unwrap(), None);
2479
2480 sheet.write(b, true).unwrap();
2481 assert_eq!(sheet.conditional_active_branch(cid).unwrap(), Some(0));
2482 assert_eq!(sheet.conditional_match_cells(cid).unwrap(), &[a, b]);
2483 }
2484
2485 #[test]
2486 fn add_conditional_returns_invalid_conditional_for_expr_output_type_mismatch() {
2487 let mut sheet = Sheet::new();
2488 let a = sheet.add_cell(0_i32);
2489 let b = sheet.add_cell(0_i32);
2490 let expr = MatchExpr::from_fn_2([a, b], |x: &i32, y: &i32| Ok(x + y));
2492 let result = sheet.add_conditional::<f64>(expr, vec![(vec![0.0], vec![])], vec![]);
2493 assert!(matches!(result, Err(Error::InvalidConditional { .. })));
2494 }
2495
2496 #[test]
2497 fn add_conditional_returns_invalid_id_for_bad_expr_input_cell() {
2498 let mut sheet = Sheet::new();
2499 let a = sheet.add_cell(0_i32);
2500 let expr = MatchExpr::from_fn_2([a, CellId::default()], |x: &i32, y: &i32| Ok(x + y));
2501 let result = sheet.add_conditional::<i32>(expr, vec![], vec![]);
2502 assert!(matches!(result, Err(Error::InvalidId)));
2503 }
2504
2505 #[test]
2506 fn propagate_surfaces_method_failed_from_a_failing_match_expression() {
2507 let mut sheet = Sheet::new();
2508 let a = sheet.add_cell(0_i32);
2509 let expr = MatchExpr::from_fn_1(a, |_x: &i32| -> Result<i32, anyhow::Error> {
2510 Err(anyhow::anyhow!("boom"))
2511 });
2512 sheet
2513 .add_conditional::<i32>(expr, vec![(vec![0], vec![])], vec![])
2514 .unwrap();
2515 let result = sheet.propagate();
2516 assert!(matches!(result, Err(Error::MethodFailed { .. })));
2517 }
2518
2519 #[test]
2520 fn add_conditional_allows_multi_method_rel_not_involving_match_cell() {
2521 let mut sheet = Sheet::new();
2522 let mode = sheet.add_cell(0_i32);
2523 let a = sheet.add_cell(0_i32);
2524 let b = sheet.add_cell(0_i32);
2525 let rel = sheet
2529 .add_relationship(vec![
2530 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
2531 Method::from_fn_1_1(b, a, |x: &i32| Ok(*x)),
2532 ])
2533 .unwrap();
2534 let result = sheet.add_conditional(
2535 MatchExpr::cell(mode),
2536 vec![(vec![0_i32], vec![rel])],
2537 vec![],
2538 );
2539 assert!(result.is_ok());
2540 }
2541
2542 #[test]
2543 fn add_conditional_returns_invalid_conditional_for_empty_branch_keys() {
2544 let mut sheet = Sheet::new();
2545 let a = sheet.add_cell(0_i32);
2546 let b = sheet.add_cell(0_i32);
2547 let rel = sheet
2548 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
2549 .unwrap();
2550 let result =
2552 sheet.add_conditional::<i32>(MatchExpr::cell(a), vec![(vec![], vec![rel])], vec![]);
2553 assert!(matches!(result, Err(Error::InvalidConditional { .. })));
2554 }
2555
2556 #[test]
2557 fn add_conditional_returns_invalid_conditional_for_duplicate_relationship_across_branches() {
2558 let mut sheet = Sheet::new();
2559 let a = sheet.add_cell(0_i32);
2560 let b = sheet.add_cell(0_i32);
2561 let rel = sheet
2562 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
2563 .unwrap();
2564 sheet
2566 .add_conditional(MatchExpr::cell(a), vec![(vec![0_i32], vec![rel])], vec![])
2567 .unwrap();
2568 let result =
2570 sheet.add_conditional(MatchExpr::cell(a), vec![(vec![1_i32], vec![rel])], vec![]);
2571 assert!(matches!(result, Err(Error::InvalidConditional { .. })));
2572 }
2573
2574 #[test]
2575 fn invalid_conditional_duplicate_relationship_names_that_relationship() {
2576 let mut sheet = Sheet::new();
2577 let a = sheet.add_cell(0_i32);
2578 let b = sheet.add_cell(0_i32);
2579 let dup_rel = sheet
2580 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
2581 .unwrap();
2582 sheet
2584 .add_conditional(
2585 MatchExpr::cell(a),
2586 vec![(vec![0_i32], vec![dup_rel])],
2587 vec![],
2588 )
2589 .unwrap();
2590 let result = sheet.add_conditional(
2592 MatchExpr::cell(a),
2593 vec![(vec![1_i32], vec![dup_rel])],
2594 vec![],
2595 );
2596 let err = result.unwrap_err();
2597 assert!(matches!(err, Error::InvalidConditional { .. }));
2598 assert!(err.sites().contains(&ErrorSite::Relationship(dup_rel)));
2599 }
2600
2601 #[test]
2602 fn add_conditional_returns_id_for_valid_input() {
2603 let mut sheet = Sheet::new();
2604 let a = sheet.add_cell(0_i32);
2605 let b = sheet.add_cell(0_i32);
2606 let rel = sheet
2607 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
2608 .unwrap();
2609 let cid = sheet
2610 .add_conditional(MatchExpr::cell(a), vec![(vec![0_i32], vec![rel])], vec![])
2611 .unwrap();
2612 let _ = cid; }
2615
2616 #[test]
2617 fn add_cell_returns_distinct_ids() {
2618 let mut sheet = Sheet::new();
2619 let a = sheet.add_cell(1_i32);
2620 let b = sheet.add_cell(2_i32);
2621 assert_ne!(a, b);
2622 }
2623
2624 #[test]
2625 fn write_returns_invalid_cell_kind_for_an_output_cell() {
2626 let mut sheet = Sheet::new();
2627 let writer_input = sheet.add_cell(1_i32);
2628 let out_cell = sheet.add_cell(0_i32);
2629 let out = sheet
2630 .add_out(
2631 Method::from_fn_1_1(writer_input, out_cell, |x: &i32| Ok(*x)),
2632 vec![],
2633 )
2634 .unwrap();
2635 assert!(matches!(
2636 sheet.write(out, 5_i32),
2637 Err(Error::InvalidCellKind { .. })
2638 ));
2639 }
2640
2641 #[test]
2642 fn add_relationship_returns_invalid_cell_kind_when_a_source_cell_is_an_output() {
2643 let mut sheet = Sheet::new();
2644 let a = sheet.add_source(0_i32);
2645 let b = sheet.add_cell(0_i32);
2646 let result = sheet.add_relationship(vec![Method::from_fn_1_1(b, a, |x: &i32| Ok(*x))]);
2647 assert!(matches!(result, Err(Error::InvalidCellKind { .. })));
2648 assert_eq!(
2649 result.unwrap_err().sites().first().copied(),
2650 Some(ErrorSite::MethodIndex(0))
2651 );
2652 }
2653
2654 #[test]
2655 fn invalid_cell_kind_names_the_method_and_the_source_output_cell() {
2656 let mut sheet = Sheet::new();
2657 let s = sheet.add_source(0_i32); let err = sheet
2660 .add_relationship(vec![Method::from_fn_1_1(s, s, |x: &i32| Ok(*x))])
2661 .unwrap_err();
2662 let sites = err.sites();
2663 assert_eq!(sites[0], ErrorSite::MethodIndex(0));
2664 assert!(sites[1..].contains(&ErrorSite::Cell(s)));
2665 }
2666
2667 #[test]
2668 fn add_relationship_allows_a_source_cell_as_an_input() {
2669 let mut sheet = Sheet::new();
2670 let a = sheet.add_source(5_i32);
2671 let b = sheet.add_cell(0_i32);
2672 let result = sheet.add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))]);
2673 assert!(result.is_ok());
2674 }
2675
2676 #[test]
2677 fn write_succeeds_on_a_source_cell() {
2678 let mut sheet = Sheet::new();
2679 let a = sheet.add_source(0_i32);
2680 assert!(sheet.write(a, 5_i32).is_ok());
2681 }
2682
2683 #[test]
2684 fn error_variant_is_invalid_cell_kind_not_terminal_cell() {
2685 let _err = Error::InvalidCellKind { sites: vec![] };
2688 }
2689
2690 #[test]
2691 fn error_has_invalid_requirement_variant() {
2692 let _err = Error::InvalidRequirement;
2693 }
2694
2695 #[test]
2696 fn write_read_roundtrip() {
2697 let mut sheet = Sheet::new();
2698 let id = sheet.add_cell(42_i32);
2699 sheet.write(id, 99_i32).unwrap();
2700 assert_eq!(*sheet.read::<i32>(id).unwrap(), 99);
2701 }
2702
2703 #[test]
2704 fn write_wrong_type_returns_type_mismatch() {
2705 let mut sheet = Sheet::new();
2706 let id = sheet.add_cell(0_i32);
2707 assert!(matches!(
2708 sheet.write(id, 1.0_f64),
2709 Err(Error::TypeMismatch { .. })
2710 ));
2711 }
2712
2713 #[test]
2714 fn read_wrong_type_returns_type_mismatch() {
2715 let mut sheet = Sheet::new();
2716 let id = sheet.add_cell(0_i32);
2717 assert!(matches!(
2718 sheet.read::<f64>(id),
2719 Err(Error::TypeMismatch { .. })
2720 ));
2721 }
2722
2723 #[test]
2724 fn source_matches_read_for_a_plain_unshadowed_cell() {
2725 let mut sheet = Sheet::new();
2726 let a = sheet.add_cell(3_i32);
2727 assert_eq!(*sheet.source::<i32>(a).unwrap(), 3);
2728 assert_eq!(*sheet.read::<i32>(a).unwrap(), 3);
2729
2730 sheet.write(a, 8_i32).unwrap();
2731 assert_eq!(*sheet.source::<i32>(a).unwrap(), 8);
2732 assert_eq!(*sheet.read::<i32>(a).unwrap(), 8);
2733 }
2734
2735 #[test]
2736 fn source_returns_invalid_id_for_unknown_cell() {
2737 let sheet = Sheet::new();
2738 assert!(matches!(
2739 sheet.source::<i32>(CellId::default()),
2740 Err(Error::InvalidId)
2741 ));
2742 }
2743
2744 #[test]
2745 fn source_wrong_type_returns_type_mismatch() {
2746 let mut sheet = Sheet::new();
2747 let id = sheet.add_cell(0_i32);
2748 assert!(matches!(
2749 sheet.source::<f64>(id),
2750 Err(Error::TypeMismatch { .. })
2751 ));
2752 }
2753
2754 #[test]
2755 fn add_relationship_empty_methods_returns_invalid_method() {
2756 let mut sheet = Sheet::new();
2757 let result = sheet.add_relationship(vec![]);
2758 assert!(matches!(result, Err(Error::InvalidMethod { .. })));
2759 assert!(result.unwrap_err().sites().is_empty());
2760 }
2761
2762 #[test]
2763 fn add_relationship_type_mismatch_returns_error() {
2764 let mut sheet = Sheet::new();
2765 let a = sheet.add_cell(0_i32);
2766 let b = sheet.add_cell(0_i32);
2767 let method = Method::from_fn_1_1(a, b, |x: &f64| Ok(*x * 2.0));
2769 let result = sheet.add_relationship(vec![method]);
2770 assert!(matches!(result, Err(Error::TypeMismatch { .. })));
2771 assert_eq!(
2772 result.unwrap_err().sites().first().copied(),
2773 Some(ErrorSite::MethodIndex(0))
2774 );
2775 }
2776
2777 #[test]
2778 fn execute_plan_type_mismatch_reports_the_method_that_produced_it() {
2779 let mut sheet = Sheet::new();
2780 let a = sheet.add_cell(0_i32);
2781 let b = sheet.add_cell(false); let method = Method::new(
2786 vec![a],
2787 vec![b],
2788 vec![TypeId::of::<i32>()],
2789 vec![TypeId::of::<bool>()],
2790 |args| {
2791 let x = *args[0].downcast_ref::<i32>().unwrap();
2792 Ok(vec![Box::new(x) as Box<dyn std::any::Any>])
2796 },
2797 );
2798 let rel_id = sheet.add_relationship(vec![method]).unwrap();
2799 let result = sheet.propagate();
2800 assert!(matches!(result, Err(Error::TypeMismatch { .. })));
2801 assert_eq!(
2802 result.unwrap_err().sites().first().copied(),
2803 Some(ErrorSite::Method(rel_id, 0))
2804 );
2805 }
2806
2807 #[test]
2808 fn execute_plan_method_failed_reports_the_method_that_produced_it() {
2809 let mut sheet = Sheet::new();
2810 let a = sheet.add_cell(0_i32);
2811 let b = sheet.add_cell(0_i32);
2812 let method = Method::from_fn_1_1(a, b, |_: &i32| -> Result<i32, anyhow::Error> {
2813 Err(anyhow::anyhow!("boom"))
2814 });
2815 let rel_id = sheet.add_relationship(vec![method]).unwrap();
2816 let result = sheet.propagate();
2817 assert!(matches!(result, Err(Error::MethodFailed { .. })));
2818 assert_eq!(
2819 result.unwrap_err().sites().first().copied(),
2820 Some(ErrorSite::Method(rel_id, 0))
2821 );
2822 }
2823
2824 #[test]
2825 fn add_relationship_zero_input_method_defines_a_fixed_point() {
2826 let mut sheet = Sheet::new();
2829 let b = sheet.add_cell(0_i32);
2830 let method = Method::new(vec![], vec![b], vec![], vec![TypeId::of::<i32>()], |_| {
2831 Ok(vec![Box::new(42_i32)])
2832 });
2833 let rel = sheet.add_relationship(vec![method]).unwrap();
2834 sheet.propagate().unwrap();
2835 assert_eq!(*sheet.read::<i32>(b).unwrap(), 42);
2836 assert!(sheet.is_forced(b));
2837 assert!(sheet.is_relationship_forced(rel));
2838 }
2839
2840 #[test]
2841 fn add_relationship_empty_outputs_returns_invalid_method() {
2842 let mut sheet = Sheet::new();
2843 let a = sheet.add_cell(0_i32);
2844 let method = Method::new(
2845 vec![a],
2846 vec![], vec![TypeId::of::<i32>()],
2848 vec![],
2849 |_| Ok(vec![]),
2850 );
2851 let result = sheet.add_relationship(vec![method]);
2852 assert!(matches!(result, Err(Error::InvalidMethod { .. })));
2853 assert_eq!(
2854 result.unwrap_err().sites().first().copied(),
2855 Some(ErrorSite::MethodIndex(0))
2856 );
2857 }
2858
2859 #[test]
2860 fn add_relationship_consistent_cell_sets_across_methods_succeeds() {
2861 let mut sheet = Sheet::new();
2862 let a = sheet.add_cell(0_i32);
2863 let b = sheet.add_cell(0_i32);
2864 let c = sheet.add_cell(0_i32);
2865 let result = sheet.add_relationship(vec![
2867 Method::from_fn_2_1([a, b], c, |x: &i32, y: &i32| Ok(x + y)),
2868 Method::from_fn_2_1([a, c], b, |x: &i32, y: &i32| Ok(y - x)),
2869 Method::from_fn_2_1([b, c], a, |x: &i32, y: &i32| Ok(y - x)),
2870 ]);
2871 assert!(result.is_ok());
2872 }
2873
2874 #[test]
2875 fn add_relationship_inconsistent_cell_sets_across_methods_returns_mismatched_method_cells() {
2876 let mut sheet = Sheet::new();
2877 let a = sheet.add_cell(0_i32);
2878 let b = sheet.add_cell(0_i32);
2879 let c = sheet.add_cell(0_i32);
2880 let result = sheet.add_relationship(vec![
2882 Method::from_fn_1_1(a, b, |v: &i32| Ok(*v)),
2883 Method::from_fn_1_1(b, c, |v: &i32| Ok(*v)),
2884 ]);
2885 assert!(matches!(result, Err(Error::MismatchedMethodCells { .. })));
2886 assert_eq!(
2887 result.unwrap_err().sites().first().copied(),
2888 Some(ErrorSite::MethodIndex(1))
2889 );
2890 }
2891
2892 #[test]
2893 fn add_relationship_distinct_output_sets_across_methods_succeeds() {
2894 let mut sheet = Sheet::new();
2895 let a = sheet.add_cell(0_i32);
2896 let b = sheet.add_cell(0_i32);
2897 let c = sheet.add_cell(0_i32);
2898 let result = sheet.add_relationship(vec![
2901 Method::from_fn_2_1([a, b], c, |x: &i32, y: &i32| Ok(x + y)),
2902 Method::from_fn_2_1([a, c], b, |x: &i32, y: &i32| Ok(y - x)),
2903 Method::from_fn_2_1([b, c], a, |x: &i32, y: &i32| Ok(y - x)),
2904 ]);
2905 assert!(result.is_ok());
2906 }
2907
2908 #[test]
2909 fn add_relationship_duplicate_output_set_across_methods_returns_invalid_method_outputs() {
2910 let mut sheet = Sheet::new();
2911 let a = sheet.add_cell(0_i32);
2912 let b = sheet.add_cell(0_i32);
2913 let result = sheet.add_relationship(vec![
2917 Method::from_fn_2_1([a, b], b, |x: &i32, _y: &i32| Ok(*x)),
2918 Method::from_fn_2_1([a, b], b, |_x: &i32, y: &i32| Ok(*y)),
2919 ]);
2920 assert!(matches!(result, Err(Error::InvalidMethodOutputs { .. })));
2921 assert_eq!(
2922 result.unwrap_err().sites().first().copied(),
2923 Some(ErrorSite::MethodIndex(1))
2924 );
2925 }
2926
2927 #[test]
2928 fn add_relationship_rejects_strictly_nested_method_outputs() {
2929 let mut sheet = Sheet::new();
2930 let a = sheet.add_cell(0_i32);
2931 let b = sheet.add_cell(0_i32);
2932 let c = sheet.add_cell(0_i32);
2933 let result = sheet.add_relationship(vec![
2935 Method::from_fn_2_1([a, c], b, |x: &i32, y: &i32| Ok(x + y)),
2936 Method::new(
2937 vec![a],
2938 vec![b, c],
2939 vec![std::any::TypeId::of::<i32>()],
2940 vec![std::any::TypeId::of::<i32>(), std::any::TypeId::of::<i32>()],
2941 |args| {
2942 let x = *args[0].downcast_ref::<i32>().unwrap();
2943 Ok(vec![Box::new(x), Box::new(x)])
2944 },
2945 ),
2946 ]);
2947 let err = result.unwrap_err();
2948 assert!(matches!(err, Error::InvalidMethodOutputs { .. }));
2949 let sites = err.sites();
2950 assert_eq!(sites[0], ErrorSite::MethodIndex(1));
2951 assert_eq!(sites[1], ErrorSite::MethodIndex(0));
2952 assert_eq!(sites[2..], [ErrorSite::Cell(b)]);
2953 }
2954
2955 #[test]
2956 fn add_relationship_accepts_overlapping_non_nested_method_outputs() {
2957 let mut sheet = Sheet::new();
2958 let a = sheet.add_cell(0_i32);
2959 let b = sheet.add_cell(0_i32);
2960 let c = sheet.add_cell(0_i32);
2961 let result = sheet.add_relationship(vec![
2963 Method::new(
2964 vec![a, c],
2965 vec![a, b],
2966 vec![std::any::TypeId::of::<i32>(), std::any::TypeId::of::<i32>()],
2967 vec![std::any::TypeId::of::<i32>(), std::any::TypeId::of::<i32>()],
2968 |args| {
2969 let x = *args[0].downcast_ref::<i32>().unwrap();
2970 let y = *args[1].downcast_ref::<i32>().unwrap();
2971 Ok(vec![Box::new(x), Box::new(y)])
2972 },
2973 ),
2974 Method::new(
2975 vec![a, b],
2976 vec![b, c],
2977 vec![std::any::TypeId::of::<i32>(), std::any::TypeId::of::<i32>()],
2978 vec![std::any::TypeId::of::<i32>(), std::any::TypeId::of::<i32>()],
2979 |args| {
2980 let x = *args[0].downcast_ref::<i32>().unwrap();
2981 let y = *args[1].downcast_ref::<i32>().unwrap();
2982 Ok(vec![Box::new(y), Box::new(x)])
2983 },
2984 ),
2985 ]);
2986 assert!(result.is_ok());
2987 }
2988
2989 #[test]
2990 fn add_relationship_returns_distinct_ids() {
2991 let mut sheet = Sheet::new();
2992 let a = sheet.add_cell(0_i32);
2993 let b = sheet.add_cell(0_i32);
2994 let r1 = sheet
2995 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
2996 .unwrap();
2997 let c = sheet.add_cell(0_i32);
2998 let r2 = sheet
2999 .add_relationship(vec![Method::from_fn_1_1(b, c, |x: &i32| Ok(*x))])
3000 .unwrap();
3001 assert_ne!(r1, r2);
3002 }
3003
3004 #[test]
3005 fn add_relationship_mismatched_cells_returns_error() {
3006 let mut sheet = Sheet::new();
3007 let a = sheet.add_cell(0_i32);
3008 let b = sheet.add_cell(0_i32);
3009 let c = sheet.add_cell(0_i32);
3010 let d = sheet.add_cell(0_i32);
3011 let result = sheet.add_relationship(vec![
3013 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
3014 Method::from_fn_1_1(c, d, |x: &i32| Ok(*x)),
3015 ]);
3016 assert!(matches!(result, Err(Error::MismatchedMethodCells { .. })));
3017 assert_eq!(
3018 result.unwrap_err().sites().first().copied(),
3019 Some(ErrorSite::MethodIndex(1))
3020 );
3021 }
3022
3023 #[test]
3024 fn add_relationship_duplicate_output_sets_across_methods_returns_error() {
3025 let mut sheet = Sheet::new();
3026 let a = sheet.add_cell(0_i32);
3027 let b = sheet.add_cell(0_i32);
3028 let c = sheet.add_cell(0_i32);
3029 let result = sheet.add_relationship(vec![
3031 Method::from_fn_2_1([a, b], c, |x: &i32, y: &i32| Ok(*x + *y)),
3032 Method::from_fn_2_1([a, b], c, |x: &i32, y: &i32| Ok(*x - *y)),
3033 ]);
3034 assert!(matches!(result, Err(Error::InvalidMethodOutputs { .. })));
3035 assert_eq!(
3036 result.unwrap_err().sites().first().copied(),
3037 Some(ErrorSite::MethodIndex(1))
3038 );
3039 }
3040
3041 #[test]
3042 fn add_relationship_duplicate_cell_within_own_outputs_returns_error() {
3043 let mut sheet = Sheet::new();
3044 let a = sheet.add_cell(0_i32);
3045 let b = sheet.add_cell(0_i32);
3046 let method = Method::new(
3048 vec![a],
3049 vec![b, b],
3050 vec![TypeId::of::<i32>()],
3051 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
3052 |args| {
3053 let x = args[0].downcast_ref::<i32>().unwrap();
3054 Ok(vec![Box::new(*x), Box::new(*x)])
3055 },
3056 );
3057 let result = sheet.add_relationship(vec![method]);
3058 assert!(matches!(result, Err(Error::InvalidMethodOutputs { .. })));
3059 assert_eq!(
3060 result.unwrap_err().sites().first().copied(),
3061 Some(ErrorSite::MethodIndex(0))
3062 );
3063 }
3064
3065 #[test]
3066 fn mismatched_method_cells_names_both_methods_and_the_differing_cell() {
3067 let mut sheet = Sheet::new();
3068 let a = sheet.add_cell(0_i32);
3069 let b = sheet.add_cell(0_i32);
3070 let c = sheet.add_cell(0_i32);
3071 let err = sheet
3073 .add_relationship(vec![
3074 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
3075 Method::from_fn_1_1(a, c, |x: &i32| Ok(*x)),
3076 ])
3077 .unwrap_err();
3078 let sites = err.sites();
3079 assert_eq!(sites[0], ErrorSite::MethodIndex(1));
3080 assert_eq!(sites[1], ErrorSite::MethodIndex(0));
3081 assert!(sites[2..].contains(&ErrorSite::Cell(c)));
3082 }
3083
3084 #[test]
3085 fn duplicate_output_set_across_methods_names_both_methods_and_the_shared_cell() {
3086 let mut sheet = Sheet::new();
3087 let a = sheet.add_cell(0_i32);
3088 let b = sheet.add_cell(0_i32);
3089 let err = sheet
3091 .add_relationship(vec![
3092 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)),
3093 Method::from_fn_1_1(a, b, |x: &i32| Ok(*x + 1)),
3094 ])
3095 .unwrap_err();
3096 let sites = err.sites();
3097 assert_eq!(sites[0], ErrorSite::MethodIndex(1));
3098 assert_eq!(sites[1], ErrorSite::MethodIndex(0));
3099 assert!(sites[2..].contains(&ErrorSite::Cell(b)));
3100 }
3101
3102 #[test]
3103 fn duplicate_cell_within_own_outputs_names_the_method_and_the_repeated_cell() {
3104 let mut sheet = Sheet::new();
3105 let a = sheet.add_cell(0_i32);
3106 let b = sheet.add_cell(0_i32);
3107 let i32_ty = std::any::TypeId::of::<i32>();
3108 let err = sheet
3110 .add_relationship(vec![Method::new(
3111 vec![a],
3112 vec![b, b],
3113 vec![i32_ty],
3114 vec![i32_ty, i32_ty],
3115 |args| {
3116 let v = *args[0].downcast_ref::<i32>().unwrap();
3117 Ok(vec![Box::new(v), Box::new(v)])
3118 },
3119 )])
3120 .unwrap_err();
3121 let sites = err.sites();
3122 assert_eq!(sites[0], ErrorSite::MethodIndex(0));
3123 assert!(sites[1..].contains(&ErrorSite::Cell(b)));
3124 }
3125
3126 #[test]
3127 fn duplicate_cell_repeated_three_times_reports_cell_once() {
3128 let mut sheet = Sheet::new();
3129 let a = sheet.add_cell(0_i32);
3130 let b = sheet.add_cell(0_i32);
3131 let i32_ty = std::any::TypeId::of::<i32>();
3132 let err = sheet
3134 .add_relationship(vec![Method::new(
3135 vec![a],
3136 vec![b, b, b],
3137 vec![i32_ty],
3138 vec![i32_ty, i32_ty, i32_ty],
3139 |args| {
3140 let v = *args[0].downcast_ref::<i32>().unwrap();
3141 Ok(vec![Box::new(v), Box::new(v), Box::new(v)])
3142 },
3143 )])
3144 .unwrap_err();
3145 let sites = err.sites();
3146 assert_eq!(sites[0], ErrorSite::MethodIndex(0));
3147 let cell_sites: Vec<_> = sites[1..]
3148 .iter()
3149 .filter(|&&s| s == ErrorSite::Cell(b))
3150 .collect();
3151 assert_eq!(
3152 cell_sites.len(),
3153 1,
3154 "expected exactly one Cell(b) site for a triple repeat, got {sites:?}"
3155 );
3156 }
3157
3158 #[test]
3159 fn changed_is_empty_before_propagate() {
3160 let sheet = Sheet::new();
3161 assert_eq!(sheet.changed().count(), 0);
3162 }
3163
3164 #[test]
3165 fn changed_after_propagate_contains_method_outputs() {
3166 let mut sheet = Sheet::new();
3167 let a = sheet.add_cell(0_i32);
3168 let b = sheet.add_cell(0_i32);
3169 sheet
3170 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
3171 .unwrap();
3172 sheet.write(a, 3_i32).unwrap();
3173 sheet.propagate().unwrap();
3174 let changed: Vec<_> = sheet.changed().collect();
3175 assert_eq!(changed, vec![b]);
3176 }
3177
3178 #[test]
3179 fn clear_changed_empties_changed_set() {
3180 let mut sheet = Sheet::new();
3181 let a = sheet.add_cell(0_i32);
3182 let b = sheet.add_cell(0_i32);
3183 sheet
3184 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
3185 .unwrap();
3186 sheet.write(a, 3_i32).unwrap();
3187 sheet.propagate().unwrap();
3188 sheet.clear_changed();
3189 assert_eq!(sheet.changed().count(), 0);
3190 }
3191
3192 #[test]
3193 fn propagate_clears_previous_changed_set() {
3194 let mut sheet = Sheet::new();
3195 let a = sheet.add_cell(0_i32);
3196 let b = sheet.add_cell(0_i32);
3197 sheet
3198 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
3199 .unwrap();
3200 sheet.write(a, 3_i32).unwrap();
3201 sheet.propagate().unwrap();
3202 sheet.write(a, 5_i32).unwrap();
3203 sheet.propagate().unwrap();
3204 let changed: Vec<_> = sheet.changed().collect();
3205 assert_eq!(changed, vec![b]);
3206 }
3207
3208 #[test]
3209 fn cells_returns_all_cell_ids() {
3210 let mut sheet = Sheet::new();
3211 let a = sheet.add_cell(0_i32);
3212 let b = sheet.add_cell(0_i32);
3213 let ids: Vec<_> = sheet.cells().collect();
3214 assert!(ids.contains(&a));
3215 assert!(ids.contains(&b));
3216 assert_eq!(ids.len(), 2);
3217 }
3218
3219 #[test]
3220 fn cells_returns_empty_for_empty_sheet() {
3221 let sheet = Sheet::new();
3222 assert_eq!(sheet.cells().count(), 0);
3223 }
3224
3225 #[test]
3226 fn relationships_returns_all_relationship_ids() {
3227 let mut sheet = Sheet::new();
3228 let a = sheet.add_cell(0_i32);
3229 let b = sheet.add_cell(0_i32);
3230 let r = sheet
3231 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3232 .unwrap();
3233 let ids: Vec<_> = sheet.relationships().collect();
3234 assert_eq!(ids, vec![r]);
3235 }
3236
3237 #[test]
3238 fn relationships_returns_empty_for_empty_sheet() {
3239 let sheet = Sheet::new();
3240 assert_eq!(sheet.relationships().count(), 0);
3241 }
3242
3243 #[test]
3244 fn cell_adj_returns_adjacent_relationships() {
3245 let mut sheet = Sheet::new();
3246 let a = sheet.add_cell(0_i32);
3247 let b = sheet.add_cell(0_i32);
3248 let r = sheet
3249 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3250 .unwrap();
3251 assert!(sheet.cell_adj(a).unwrap().contains(&r));
3252 assert!(sheet.cell_adj(b).unwrap().contains(&r));
3253 }
3254
3255 #[test]
3256 fn cell_adj_returns_none_for_invalid_id() {
3257 let sheet = Sheet::new();
3258 assert!(sheet.cell_adj(CellId::default()).is_none());
3259 }
3260
3261 #[test]
3262 fn relationship_adj_returns_adjacent_cells() {
3263 let mut sheet = Sheet::new();
3264 let a = sheet.add_cell(0_i32);
3265 let b = sheet.add_cell(0_i32);
3266 let r = sheet
3267 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3268 .unwrap();
3269 let adj = sheet.relationship_adj(r).unwrap();
3270 assert!(adj.contains(&a));
3271 assert!(adj.contains(&b));
3272 }
3273
3274 #[test]
3275 fn relationship_adj_returns_none_for_invalid_id() {
3276 let sheet = Sheet::new();
3277 assert!(sheet.relationship_adj(RelationshipId::default()).is_none());
3278 }
3279
3280 #[test]
3281 fn selected_method_returns_none_before_propagate() {
3282 let mut sheet = Sheet::new();
3283 let a = sheet.add_cell(0_i32);
3284 let b = sheet.add_cell(0_i32);
3285 let rel = sheet
3286 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3287 .unwrap();
3288 assert!(sheet.selected_method(rel).is_none());
3289 }
3290
3291 #[test]
3292 fn selected_method_returns_index_after_propagate() {
3293 let mut sheet = Sheet::new();
3294 let a = sheet.add_cell(0_i32);
3295 let b = sheet.add_cell(0_i32);
3296 let rel = sheet
3297 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3298 .unwrap();
3299 sheet.write(a, 0_i32).unwrap();
3302 sheet.propagate().unwrap();
3303 assert_eq!(sheet.selected_method(rel), Some(0));
3304 }
3305
3306 #[test]
3307 fn method_inputs_returns_inputs_for_valid_method() {
3308 let mut sheet = Sheet::new();
3309 let a = sheet.add_cell(0_i32);
3310 let b = sheet.add_cell(0_i32);
3311 let rel = sheet
3312 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3313 .unwrap();
3314 assert_eq!(sheet.method_inputs(rel, 0), Some([a].as_slice()));
3315 }
3316
3317 #[test]
3318 fn method_outputs_returns_outputs_for_valid_method() {
3319 let mut sheet = Sheet::new();
3320 let a = sheet.add_cell(0_i32);
3321 let b = sheet.add_cell(0_i32);
3322 let rel = sheet
3323 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3324 .unwrap();
3325 assert_eq!(sheet.method_outputs(rel, 0), Some([b].as_slice()));
3326 }
3327
3328 #[test]
3329 fn method_inputs_returns_none_for_out_of_bounds_idx() {
3330 let mut sheet = Sheet::new();
3331 let a = sheet.add_cell(0_i32);
3332 let b = sheet.add_cell(0_i32);
3333 let rel = sheet
3334 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3335 .unwrap();
3336 assert!(sheet.method_inputs(rel, 99).is_none());
3337 }
3338
3339 #[test]
3340 fn method_outputs_returns_none_for_out_of_bounds_idx() {
3341 let mut sheet = Sheet::new();
3342 let a = sheet.add_cell(0_i32);
3343 let b = sheet.add_cell(0_i32);
3344 let rel = sheet
3345 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3346 .unwrap();
3347 assert!(sheet.method_outputs(rel, 99).is_none());
3348 }
3349
3350 #[test]
3351 fn is_source_returns_false_before_propagate() {
3352 let mut sheet = Sheet::new();
3353 let a = sheet.add_cell(0_i32);
3354 let b = sheet.add_cell(0_i32);
3355 sheet
3356 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3357 .unwrap();
3358 assert!(!sheet.is_source(a));
3359 }
3360
3361 #[test]
3362 fn is_source_returns_true_for_input_cell_after_propagate() {
3363 let mut sheet = Sheet::new();
3364 let a = sheet.add_cell(0_i32);
3365 let b = sheet.add_cell(0_i32);
3366 sheet
3367 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3368 .unwrap();
3369 sheet.write(a, 0_i32).unwrap();
3371 sheet.propagate().unwrap();
3372 assert!(sheet.is_source(a));
3373 }
3374
3375 #[test]
3376 fn is_source_returns_false_for_output_cell_after_propagate() {
3377 let mut sheet = Sheet::new();
3378 let a = sheet.add_cell(0_i32);
3379 let b = sheet.add_cell(0_i32);
3380 sheet
3381 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3382 .unwrap();
3383 sheet.write(a, 0_i32).unwrap();
3385 sheet.propagate().unwrap();
3386 assert!(!sheet.is_source(b));
3387 }
3388
3389 fn sheet_with_two_branch_conditional() -> (Sheet, ConditionalId) {
3392 let mut sheet = Sheet::new();
3393 let a = sheet.add_cell(0_i32);
3394 let b = sheet.add_cell(0_i32);
3395 let p = sheet.add_cell(0_i32);
3396
3397 let rel0 = sheet
3398 .add_relationship(vec![Method::from_fn_1_1(a, b, |v: &i32| Ok(*v))])
3399 .unwrap();
3400 let rel1 = sheet
3401 .add_relationship(vec![Method::from_fn_1_1(b, a, |v: &i32| Ok(*v))])
3402 .unwrap();
3403
3404 let cid = sheet
3405 .add_conditional(
3406 MatchExpr::cell(p),
3407 vec![(vec![0_i32], vec![rel0]), (vec![1_i32], vec![rel1])],
3408 vec![],
3409 )
3410 .unwrap();
3411 (sheet, cid)
3412 }
3413
3414 fn sheet_with_default_conditional() -> (Sheet, ConditionalId, RelationshipId) {
3415 let mut sheet = Sheet::new();
3416 let a = sheet.add_cell(0_i32);
3417 let b = sheet.add_cell(0_i32);
3418 let p = sheet.add_cell(99_i32); let rel_default = sheet
3421 .add_relationship(vec![Method::from_fn_1_1(a, b, |v: &i32| Ok(*v))])
3422 .unwrap();
3423
3424 let cid = sheet
3425 .add_conditional::<i32>(MatchExpr::cell(p), vec![], vec![rel_default])
3426 .unwrap();
3427 (sheet, cid, rel_default)
3428 }
3429
3430 #[test]
3431 fn conditionals_returns_registered_id() {
3432 let (sheet, cid) = sheet_with_two_branch_conditional();
3433 assert!(sheet.conditionals().any(|id| id == cid));
3434 }
3435
3436 #[test]
3437 fn conditionals_empty_on_new_sheet() {
3438 let sheet = Sheet::new();
3439 assert_eq!(sheet.conditionals().count(), 0);
3440 }
3441
3442 #[test]
3443 fn conditional_match_cells_returns_correct_cell() {
3444 let mut sheet = Sheet::new();
3445 let p = sheet.add_cell(0_i32);
3446 let cid = sheet
3447 .add_conditional::<i32>(MatchExpr::cell(p), vec![], vec![])
3448 .unwrap();
3449 assert_eq!(sheet.conditional_match_cells(cid), Some([p].as_slice()));
3450 }
3451
3452 #[test]
3453 fn conditional_match_cells_returns_none_for_invalid_id() {
3454 let sheet = Sheet::new();
3455 assert_eq!(
3456 sheet.conditional_match_cells(ConditionalId::default()),
3457 None
3458 );
3459 }
3460
3461 #[test]
3462 fn conditional_branch_count_returns_correct_count() {
3463 let (sheet, cid) = sheet_with_two_branch_conditional();
3464 assert_eq!(sheet.conditional_branch_count(cid), Some(2));
3465 }
3466
3467 #[test]
3468 fn conditional_branch_count_returns_none_for_invalid_id() {
3469 let sheet = Sheet::new();
3470 assert_eq!(
3471 sheet.conditional_branch_count(ConditionalId::default()),
3472 None
3473 );
3474 }
3475
3476 #[test]
3477 fn conditional_branch_relationships_returns_correct_rels() {
3478 let (sheet, cid) = sheet_with_two_branch_conditional();
3479 let rels0 = sheet.conditional_branch_relationships(cid, 0).unwrap();
3480 let rels1 = sheet.conditional_branch_relationships(cid, 1).unwrap();
3481 assert_eq!(rels0.len(), 1);
3482 assert_eq!(rels1.len(), 1);
3483 assert_ne!(rels0[0], rels1[0]);
3484 }
3485
3486 #[test]
3487 fn conditional_branch_relationships_returns_none_for_out_of_bounds() {
3488 let (sheet, cid) = sheet_with_two_branch_conditional();
3489 assert!(sheet.conditional_branch_relationships(cid, 2).is_none());
3490 }
3491
3492 #[test]
3493 fn conditional_branch_relationships_returns_none_for_invalid_id() {
3494 let sheet = Sheet::new();
3495 assert!(
3496 sheet
3497 .conditional_branch_relationships(ConditionalId::default(), 0)
3498 .is_none()
3499 );
3500 }
3501
3502 #[test]
3503 fn conditional_default_relationships_returns_correct_rels() {
3504 let (sheet, cid, rel_default) = sheet_with_default_conditional();
3505 let rels = sheet.conditional_default_relationships(cid).unwrap();
3506 assert_eq!(rels, [rel_default]);
3507 }
3508
3509 #[test]
3510 fn conditional_default_relationships_empty_when_no_default() {
3511 let (sheet, cid) = sheet_with_two_branch_conditional();
3512 assert_eq!(sheet.conditional_default_relationships(cid).unwrap(), &[]);
3513 }
3514
3515 #[test]
3516 fn conditional_default_relationships_returns_none_for_invalid_id() {
3517 let sheet = Sheet::new();
3518 assert!(
3519 sheet
3520 .conditional_default_relationships(ConditionalId::default())
3521 .is_none()
3522 );
3523 }
3524
3525 #[test]
3526 fn conditional_active_branch_returns_matching_branch_index() {
3527 let (mut sheet, cid) = sheet_with_two_branch_conditional();
3528 let p = sheet.conditional_match_cells(cid).unwrap()[0];
3529 sheet.write(p, 0_i32).unwrap();
3530 assert_eq!(sheet.conditional_active_branch(cid).unwrap(), Some(0));
3531 sheet.write(p, 1_i32).unwrap();
3532 assert_eq!(sheet.conditional_active_branch(cid).unwrap(), Some(1));
3533 }
3534
3535 #[test]
3536 fn conditional_active_branch_returns_none_when_no_branch_matches() {
3537 let (mut sheet, cid) = sheet_with_two_branch_conditional();
3538 let p = sheet.conditional_match_cells(cid).unwrap()[0];
3539 sheet.write(p, 99_i32).unwrap();
3540 assert_eq!(sheet.conditional_active_branch(cid).unwrap(), None);
3541 }
3542
3543 #[test]
3544 fn conditional_active_branch_returns_none_for_invalid_id() {
3545 let sheet = Sheet::new();
3546 assert_eq!(
3547 sheet
3548 .conditional_active_branch(ConditionalId::default())
3549 .unwrap(),
3550 None
3551 );
3552 }
3553
3554 #[test]
3555 fn add_filter_returns_invalid_id_for_missing_cell() {
3556 let mut sheet = Sheet::new();
3557 let result = sheet.add_filter(CellId::default(), Filter::from_fn_0(|x: &i32| Ok(*x)));
3558 assert!(matches!(result, Err(Error::InvalidId)));
3559 }
3560
3561 #[test]
3562 fn add_filter_does_not_change_the_cells_current_value() {
3563 let mut sheet = Sheet::new();
3564 let a = sheet.add_cell(500_i32);
3565 sheet
3566 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3567 .unwrap();
3568 assert_eq!(*sheet.read::<i32>(a).unwrap(), 500);
3571 }
3572
3573 #[test]
3574 fn propagate_after_add_filter_conforms_the_initial_value() {
3575 let mut sheet = Sheet::new();
3576 let a = sheet.add_cell(500_i32);
3577 sheet
3578 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3579 .unwrap();
3580 assert_eq!(*sheet.read::<i32>(a).unwrap(), 500);
3581 sheet.propagate().unwrap();
3582 assert_eq!(*sheet.read::<i32>(a).unwrap(), 100);
3585 }
3586
3587 #[test]
3588 fn add_filter_returns_invalid_filter_when_cell_already_has_a_filter() {
3589 let mut sheet = Sheet::new();
3590 let a = sheet.add_cell(5_i32);
3591 sheet
3592 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok(*x)))
3593 .unwrap();
3594 let result = sheet.add_filter(a, Filter::from_fn_0(|x: &i32| Ok(*x)));
3595 assert!(matches!(result, Err(Error::InvalidFilter)));
3596 }
3597
3598 #[test]
3599 fn add_filter_returns_invalid_filter_for_mismatched_value_type() {
3600 let mut sheet = Sheet::new();
3601 let a = sheet.add_cell(5_i32);
3602 let result = sheet.add_filter(a, Filter::from_fn_0(|x: &f64| Ok(*x)));
3603 assert!(matches!(result, Err(Error::InvalidFilter)));
3604 }
3605
3606 #[test]
3607 fn add_filter_returns_invalid_filter_when_args_name_the_filtered_cell_itself() {
3608 let mut sheet = Sheet::new();
3609 let a = sheet.add_cell(5_i32);
3610 let result = sheet.add_filter(
3611 a,
3612 Filter::from_fn_1(a, |x: &i32, bound: &i32| Ok((*x).min(*bound))),
3613 );
3614 assert!(matches!(result, Err(Error::InvalidFilter)));
3615 }
3616
3617 #[test]
3618 fn add_filter_returns_invalid_id_for_missing_arg_cell() {
3619 let mut sheet = Sheet::new();
3620 let a = sheet.add_cell(5_i32);
3621 let result = sheet.add_filter(
3622 a,
3623 Filter::from_fn_1(CellId::default(), |x: &i32, bound: &i32| {
3624 Ok((*x).min(*bound))
3625 }),
3626 );
3627 assert!(matches!(result, Err(Error::InvalidId)));
3628 }
3629
3630 #[test]
3631 fn add_filter_returns_type_mismatch_for_wrong_arg_cell_type() {
3632 let mut sheet = Sheet::new();
3633 let a = sheet.add_cell(5_i32);
3634 let bound = sheet.add_cell(1.0_f64); let result = sheet.add_filter(
3636 a,
3637 Filter::from_fn_1(bound, |x: &i32, bound: &i32| Ok((*x).min(*bound))),
3638 );
3639 assert!(matches!(result, Err(Error::TypeMismatch { .. })));
3640 }
3641
3642 #[test]
3643 fn add_filter_succeeds_on_a_source_kind_cell() {
3644 let mut sheet = Sheet::new();
3645 let a = sheet.add_source(5_i32);
3646 assert!(
3647 sheet
3648 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 10))))
3649 .is_ok()
3650 );
3651 }
3652
3653 #[test]
3654 fn from_fn_2_conforms_values_through_sheet_using_both_dynamic_arguments() {
3655 let mut sheet = Sheet::new();
3656 let a = sheet.add_cell(500_i32);
3657 let lo = sheet.add_cell(0_i32);
3658 let hi = sheet.add_cell(100_i32);
3659 sheet
3660 .add_filter(
3661 a,
3662 Filter::from_fn_2([lo, hi], |x: &i32, lo: &i32, hi: &i32| {
3663 Ok((*x).clamp(*lo, *hi))
3664 }),
3665 )
3666 .unwrap();
3667 sheet.propagate().unwrap();
3668 assert_eq!(*sheet.read::<i32>(a).unwrap(), 100);
3669
3670 sheet.write(a, -10_i32).unwrap();
3671 sheet.propagate().unwrap();
3672 assert_eq!(*sheet.read::<i32>(a).unwrap(), 0);
3673 }
3674
3675 #[test]
3676 fn write_without_a_filter_behaves_exactly_as_before() {
3677 let mut sheet = Sheet::new();
3678 let a = sheet.add_cell(0_i32);
3679 sheet.write(a, 42_i32).unwrap();
3680 assert_eq!(*sheet.read::<i32>(a).unwrap(), 42);
3681 }
3682
3683 #[test]
3684 fn write_leaves_the_raw_value_in_source_until_propagate_conforms_it() {
3685 let mut sheet = Sheet::new();
3686 let a = sheet.add_cell(0_i32);
3687 sheet
3688 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3689 .unwrap();
3690 sheet.write(a, 500_i32).unwrap();
3691 assert_eq!(*sheet.read::<i32>(a).unwrap(), 500);
3693 sheet.propagate().unwrap();
3694 assert_eq!(*sheet.read::<i32>(a).unwrap(), 100);
3695 }
3696
3697 #[test]
3698 fn propagate_reports_no_violation_when_a_derived_value_conforms() {
3699 let mut sheet = Sheet::new();
3700 let a = sheet.add_cell(10_i32);
3701 let b = sheet.add_cell(0_i32);
3702 sheet
3703 .add_filter(b, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3704 .unwrap();
3705 sheet
3706 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3707 .unwrap();
3708 sheet.propagate().unwrap();
3709 assert_eq!(*sheet.read::<i32>(b).unwrap(), 10);
3710 assert!(sheet.last_filter_violations.is_empty());
3711 }
3712
3713 #[test]
3714 fn propagate_reports_not_conformed_when_a_derived_value_violates_its_filter() {
3715 let mut sheet = Sheet::new();
3716 let a = sheet.add_cell(60_i32);
3717 let b = sheet.add_cell(0_i32);
3718 sheet
3719 .add_filter(b, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3720 .unwrap();
3721 sheet
3722 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
3723 .unwrap();
3724 sheet.propagate().unwrap();
3725 assert_eq!(*sheet.read::<i32>(b).unwrap(), 120);
3727 assert!(matches!(
3728 sheet.last_filter_violations.get(&b),
3729 Some(FilterViolation::NotConformed)
3730 ));
3731 }
3732
3733 #[test]
3734 fn propagate_reports_failed_when_the_filter_errors_on_a_derived_value() {
3735 let mut sheet = Sheet::new();
3736 let a = sheet.add_cell(1_i32);
3737 let b = sheet.add_cell(0_i32);
3738 sheet
3743 .add_filter(
3744 b,
3745 Filter::from_fn_0(|x: &i32| {
3746 if *x == 0 {
3747 Ok(*x)
3748 } else {
3749 Err(anyhow::anyhow!("cannot conform"))
3750 }
3751 }),
3752 )
3753 .unwrap();
3754 sheet
3755 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3756 .unwrap();
3757 sheet.propagate().unwrap();
3759 assert!(matches!(
3760 sheet.last_filter_violations.get(&b),
3761 Some(FilterViolation::Failed(_))
3762 ));
3763 }
3764
3765 #[test]
3766 fn propagate_reports_failed_when_the_filter_returns_the_wrong_type_on_a_derived_value() {
3767 let mut sheet = Sheet::new();
3768 let a = sheet.add_cell(1_i32);
3769 let b = sheet.add_cell(0_i32);
3770 let filter = Filter::new(TypeId::of::<i32>(), vec![], vec![], |value, _args| {
3775 let v = *value.downcast_ref::<i32>().unwrap();
3776 if v == 0 {
3777 Ok(Box::new(v) as Box<dyn Any>)
3778 } else {
3779 Ok(Box::new(1.5_f64) as Box<dyn Any>)
3780 }
3781 });
3782 sheet.add_filter(b, filter).unwrap();
3783 sheet
3784 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
3785 .unwrap();
3786 sheet.propagate().unwrap();
3789 assert!(matches!(
3790 sheet.filter_violation(b),
3791 Some(FilterViolation::Failed(_))
3792 ));
3793 }
3794
3795 #[test]
3796 fn propagate_never_flags_a_filtered_cell_that_stayed_a_plain_source() {
3797 let mut sheet = Sheet::new();
3798 let a = sheet.add_cell(60_i32);
3799 sheet
3800 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3801 .unwrap();
3802 sheet.propagate().unwrap();
3803 assert!(sheet.last_filter_violations.is_empty());
3804 }
3805
3806 #[test]
3807 fn propagate_reclamps_a_filtered_source_cell_when_its_argument_changes() {
3808 let mut sheet = Sheet::new();
3810 let a = sheet.add_cell(50_i32);
3811 let bound = sheet.add_cell(100_i32);
3812 sheet
3813 .add_filter(
3814 a,
3815 Filter::from_fn_1(bound, |v: &i32, b: &i32| Ok((*v).min(*b))),
3816 )
3817 .unwrap();
3818 sheet.write(bound, 10_i32).unwrap();
3819 sheet.propagate().unwrap();
3820 assert_eq!(*sheet.read::<i32>(a).unwrap(), 10);
3821 }
3822
3823 #[test]
3824 fn propagate_reclamps_before_a_relationship_consumes_the_reclamped_value() {
3825 let mut sheet = Sheet::new();
3835 let b = sheet.add_cell(20_i32);
3836 let a = sheet.add_cell(50_i32);
3837 let bound = sheet.add_cell(100_i32);
3838 sheet
3839 .add_filter(
3840 a,
3841 Filter::from_fn_1(bound, |v: &i32, bnd: &i32| Ok((*v).min(*bnd))),
3842 )
3843 .unwrap();
3844 sheet
3845 .add_relationship(vec![
3846 Method::from_fn_2_1([a, b], b, |x: &i32, y: &i32| Ok((*x).min(*y))),
3847 Method::from_fn_2_1([a, b], a, |x: &i32, y: &i32| Ok((*x).max(*y))),
3848 ])
3849 .unwrap();
3850 sheet.propagate().unwrap();
3851
3852 sheet.write(bound, 5_i32).unwrap();
3853 sheet.propagate().unwrap();
3854
3855 assert_eq!(*sheet.read::<i32>(a).unwrap(), 5);
3858 assert_eq!(*sheet.read::<i32>(b).unwrap(), 5);
3859 }
3860
3861 #[test]
3862 fn filtered_source_cell_springs_back_to_its_original_value_when_a_bound_loosens() {
3863 let mut sheet = Sheet::new();
3864 let a = sheet.add_cell(50_i32);
3865 let bound = sheet.add_cell(100_i32);
3866 sheet
3867 .add_filter(
3868 a,
3869 Filter::from_fn_1(bound, |v: &i32, b: &i32| Ok((*v).min(*b))),
3870 )
3871 .unwrap();
3872
3873 sheet.write(bound, 10_i32).unwrap();
3874 sheet.propagate().unwrap();
3875 assert_eq!(*sheet.read::<i32>(a).unwrap(), 10);
3876
3877 sheet.write(bound, 100_i32).unwrap();
3878 sheet.propagate().unwrap();
3879 assert_eq!(*sheet.read::<i32>(a).unwrap(), 50);
3883 }
3884
3885 #[test]
3886 fn filter_reclamp_records_failed_violation_when_the_filters_function_returns_the_wrong_type() {
3887 let mut sheet = Sheet::new();
3888 let a = sheet.add_cell(5_i32);
3889 let trigger = sheet.add_cell(0_i32);
3890 let filter = Filter::new(
3894 TypeId::of::<i32>(),
3895 vec![trigger],
3896 vec![TypeId::of::<i32>()],
3897 |value, args| {
3898 let v = *value.downcast_ref::<i32>().unwrap();
3899 let t = *args[0].downcast_ref::<i32>().unwrap();
3900 if t == 0 {
3901 Ok(Box::new(v) as Box<dyn Any>)
3902 } else {
3903 Ok(Box::new(1.5_f64) as Box<dyn Any>)
3904 }
3905 },
3906 );
3907 sheet.add_filter(a, filter).unwrap();
3908
3909 sheet.write(trigger, 1_i32).unwrap();
3911 sheet.propagate().unwrap();
3912
3913 assert!(matches!(
3914 sheet.filter_violation(a),
3915 Some(FilterViolation::Failed(_))
3916 ));
3917 assert_eq!(*sheet.read::<i32>(a).unwrap(), 5);
3919 }
3920
3921 #[test]
3922 fn filter_reclamp_failure_is_recorded_without_aborting_propagate_or_changing_the_cell() {
3923 let mut sheet = Sheet::new();
3924 let a = sheet.add_cell(5_i32);
3925 let bound = sheet.add_cell(100_i32);
3926 sheet
3929 .add_filter(
3930 a,
3931 Filter::from_fn_1(bound, |v: &i32, b: &i32| {
3932 if *v <= *b {
3933 Ok(*v)
3934 } else {
3935 Err(anyhow::anyhow!("cannot conform"))
3936 }
3937 }),
3938 )
3939 .unwrap();
3940 sheet.write(bound, 0_i32).unwrap();
3941
3942 sheet.propagate().unwrap();
3943
3944 assert!(matches!(
3945 sheet.filter_violation(a),
3946 Some(FilterViolation::Failed(_))
3947 ));
3948 assert_eq!(*sheet.read::<i32>(a).unwrap(), 5);
3950 }
3951
3952 #[test]
3953 fn filter_args_returns_the_filters_argument_cells() {
3954 let mut sheet = Sheet::new();
3955 let a = sheet.add_cell(5_i32);
3956 let bound = sheet.add_cell(10_i32);
3957 sheet
3958 .add_filter(
3959 a,
3960 Filter::from_fn_1(bound, |x: &i32, bound: &i32| Ok((*x).min(*bound))),
3961 )
3962 .unwrap();
3963 assert_eq!(sheet.filter_args(a), Some(&[bound][..]));
3964 }
3965
3966 #[test]
3967 fn filter_args_returns_none_for_a_cell_with_no_filter() {
3968 let mut sheet = Sheet::new();
3969 let a = sheet.add_cell(5_i32);
3970 assert_eq!(sheet.filter_args(a), None);
3971 }
3972
3973 #[test]
3974 fn filter_args_returns_none_for_an_invalid_cell() {
3975 let sheet = Sheet::new();
3976 assert_eq!(sheet.filter_args(CellId::default()), None);
3977 }
3978
3979 #[test]
3980 fn filter_violation_returns_none_before_any_propagate() {
3981 let sheet = Sheet::new();
3982 assert!(sheet.filter_violation(CellId::default()).is_none());
3983 }
3984
3985 #[test]
3986 fn filter_violated_cells_reports_a_currently_violated_filter() {
3987 let mut sheet = Sheet::new();
3988 let a = sheet.add_cell(60_i32);
3989 let b = sheet.add_cell(0_i32);
3990 sheet
3991 .add_filter(b, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
3992 .unwrap();
3993 sheet
3994 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
3995 .unwrap();
3996 sheet.propagate().unwrap();
3997 assert!(sheet.filter_violated_cells().any(|id| id == b));
3998 assert!(matches!(
3999 sheet.filter_violation(b),
4000 Some(FilterViolation::NotConformed)
4001 ));
4002 }
4003
4004 #[test]
4005 fn filter_violation_cells_is_empty_when_nothing_is_violated() {
4006 let mut sheet = Sheet::new();
4007 let a = sheet.add_cell(10_i32);
4008 sheet
4009 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 100))))
4010 .unwrap();
4011 sheet.propagate().unwrap();
4012 assert!(sheet.filter_violation_cells().is_empty());
4013 }
4014
4015 #[test]
4016 fn filter_violation_cells_includes_root_causes_of_a_violation() {
4017 let mut sheet = Sheet::new();
4018 let a = sheet.add_cell(60_i32);
4019 let bound = sheet.add_cell(100_i32);
4020 let b = sheet.add_cell(0_i32);
4021 sheet
4022 .add_filter(
4023 b,
4024 Filter::from_fn_1(bound, |x: &i32, bound: &i32| Ok((*x).min(*bound))),
4025 )
4026 .unwrap();
4027 sheet
4028 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))])
4029 .unwrap();
4030 sheet.propagate().unwrap();
4031 let violation_cells = sheet.filter_violation_cells();
4032 assert!(violation_cells.contains(&a));
4037 assert!(violation_cells.contains(&bound));
4038 }
4039
4040 #[test]
4041 fn filter_violation_cells_includes_root_causes_of_a_failed_violation() {
4042 let mut sheet = Sheet::new();
4043 let a = sheet.add_cell(1_i32);
4044 let bound = sheet.add_cell(100_i32);
4045 let b = sheet.add_cell(0_i32);
4046 sheet
4050 .add_filter(
4051 b,
4052 Filter::from_fn_1(bound, |x: &i32, _bound: &i32| {
4053 if *x == 0 {
4054 Ok(*x)
4055 } else {
4056 Err(anyhow::anyhow!("cannot conform"))
4057 }
4058 }),
4059 )
4060 .unwrap();
4061 sheet
4062 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
4063 .unwrap();
4064 sheet.propagate().unwrap();
4065 assert!(matches!(
4066 sheet.filter_violation(b),
4067 Some(FilterViolation::Failed(_))
4068 ));
4069 let violation_cells = sheet.filter_violation_cells();
4070 assert!(violation_cells.contains(&a));
4073 assert!(violation_cells.contains(&bound));
4074 }
4075
4076 #[test]
4077 fn filter_dependents_returns_the_cells_whose_filter_references_this_one() {
4078 let mut sheet = Sheet::new();
4079 let bound = sheet.add_cell(10_i32);
4080 let a = sheet.add_cell(5_i32);
4081 sheet
4082 .add_filter(
4083 a,
4084 Filter::from_fn_1(bound, |v: &i32, b: &i32| Ok((*v).min(*b))),
4085 )
4086 .unwrap();
4087 assert_eq!(sheet.filter_dependents(bound), &[a]);
4088 }
4089
4090 #[test]
4091 fn filter_dependents_is_empty_for_a_cell_no_filter_references() {
4092 let mut sheet = Sheet::new();
4093 let bound = sheet.add_cell(10_i32);
4094 let a = sheet.add_cell(5_i32);
4095 sheet
4096 .add_filter(a, Filter::from_fn_0(|v: &i32| Ok((*v).clamp(0, 100))))
4097 .unwrap();
4098 assert!(sheet.filter_dependents(bound).is_empty());
4099 }
4100
4101 #[test]
4102 fn filter_dependents_is_empty_for_an_invalid_cell() {
4103 let sheet = Sheet::new();
4104 assert!(sheet.filter_dependents(CellId::default()).is_empty());
4105 }
4106
4107 #[test]
4108 fn filter_dependents_aggregates_multiple_dependents_of_the_same_argument() {
4109 let mut sheet = Sheet::new();
4110 let bound = sheet.add_cell(10_i32);
4111 let a = sheet.add_cell(5_i32);
4112 let b = sheet.add_cell(5_i32);
4113 sheet
4114 .add_filter(
4115 a,
4116 Filter::from_fn_1(bound, |v: &i32, bd: &i32| Ok((*v).min(*bd))),
4117 )
4118 .unwrap();
4119 sheet
4120 .add_filter(
4121 b,
4122 Filter::from_fn_1(bound, |v: &i32, bd: &i32| Ok((*v).min(*bd))),
4123 )
4124 .unwrap();
4125 let dependents = sheet.filter_dependents(bound);
4126 assert_eq!(dependents.len(), 2);
4127 assert!(dependents.contains(&a));
4128 assert!(dependents.contains(&b));
4129 }
4130
4131 #[test]
4132 fn filter_kind_returns_none_for_a_cell_with_no_filter() {
4133 let mut sheet = Sheet::new();
4134 let a = sheet.add_cell(0_i32);
4135 assert!(sheet.filter_kind(a).is_none());
4136 }
4137
4138 #[test]
4139 fn filter_kind_returns_opaque_for_a_plain_filter() {
4140 let mut sheet = Sheet::new();
4141 let a = sheet.add_cell(0_i32);
4142 sheet
4143 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok(*x)))
4144 .unwrap();
4145 assert!(matches!(sheet.filter_kind(a), Some(FilterKind::Opaque)));
4146 }
4147
4148 #[test]
4149 fn filter_kind_returns_range_for_a_range_filter() {
4150 let mut sheet = Sheet::new();
4151 let a = sheet.add_cell(0_i32);
4152 let filter = Filter::range(
4153 TypeId::of::<i32>(),
4154 vec![],
4155 vec![],
4156 |value, _args| Ok(Box::new(*value.downcast_ref::<i32>().unwrap()) as Box<dyn Any>),
4157 |_args| {
4158 Some((
4159 Box::new(0i32) as Box<dyn Any>,
4160 Box::new(100i32) as Box<dyn Any>,
4161 ))
4162 },
4163 );
4164 sheet.add_filter(a, filter).unwrap();
4165 assert!(matches!(
4166 sheet.filter_kind(a),
4167 Some(FilterKind::Range { .. })
4168 ));
4169 }
4170
4171 #[test]
4172 fn filter_range_returns_live_bounds_from_argument_cells() {
4173 let mut sheet = Sheet::new();
4174 let a = sheet.add_cell(0_i32);
4175 let lo = sheet.add_cell(0_i32);
4176 let hi = sheet.add_cell(100_i32);
4177 let filter = Filter::range(
4178 TypeId::of::<i32>(),
4179 vec![lo, hi],
4180 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
4181 |value, args| {
4182 let v = *value.downcast_ref::<i32>().unwrap();
4183 let lo = *args[0].downcast_ref::<i32>().unwrap();
4184 let hi = *args[1].downcast_ref::<i32>().unwrap();
4185 Ok(Box::new(v.clamp(lo, hi)) as Box<dyn Any>)
4186 },
4187 |args| {
4188 Some((
4189 Box::new(*args[0].downcast_ref::<i32>().unwrap()) as Box<dyn Any>,
4190 Box::new(*args[1].downcast_ref::<i32>().unwrap()) as Box<dyn Any>,
4191 ))
4192 },
4193 );
4194 sheet.add_filter(a, filter).unwrap();
4195 assert_eq!(sheet.filter_range::<i32>(a), Some((0, 100)));
4196 sheet.write(hi, 10_i32).unwrap();
4197 assert_eq!(sheet.filter_range::<i32>(a), Some((0, 10)));
4198 }
4199
4200 #[test]
4201 fn filter_range_reflects_a_bound_derived_by_a_relationship_not_just_a_direct_write() {
4202 let mut sheet = Sheet::new();
4206 let a = sheet.add_cell(0_i32);
4207 let lo = sheet.add_cell(0_i32);
4208 let hi = sheet.add_cell(100_i32);
4209 let hi_source = sheet.add_cell(100_i32);
4210 sheet
4211 .add_relationship(vec![Method::from_fn_1_1(hi_source, hi, |v: &i32| Ok(*v))])
4212 .unwrap();
4213 let filter = Filter::range(
4214 TypeId::of::<i32>(),
4215 vec![lo, hi],
4216 vec![TypeId::of::<i32>(), TypeId::of::<i32>()],
4217 |value, args| {
4218 let v = *value.downcast_ref::<i32>().unwrap();
4219 let lo = *args[0].downcast_ref::<i32>().unwrap();
4220 let hi = *args[1].downcast_ref::<i32>().unwrap();
4221 Ok(Box::new(v.clamp(lo, hi)) as Box<dyn Any>)
4222 },
4223 |args| {
4224 Some((
4225 Box::new(*args[0].downcast_ref::<i32>().unwrap()) as Box<dyn Any>,
4226 Box::new(*args[1].downcast_ref::<i32>().unwrap()) as Box<dyn Any>,
4227 ))
4228 },
4229 );
4230 sheet.add_filter(a, filter).unwrap();
4231 sheet.write(hi_source, 20_i32).unwrap();
4232 sheet.propagate().unwrap();
4233 assert_eq!(sheet.filter_range::<i32>(a), Some((0, 20)));
4234 }
4235
4236 #[test]
4237 fn filter_range_returns_none_for_an_opaque_filter() {
4238 let mut sheet = Sheet::new();
4239 let a = sheet.add_cell(0_i32);
4240 sheet
4241 .add_filter(a, Filter::from_fn_0(|x: &i32| Ok(*x)))
4242 .unwrap();
4243 assert!(sheet.filter_range::<i32>(a).is_none());
4244 }
4245
4246 #[test]
4247 fn add_requirement_succeeds_on_a_plain_cell() {
4248 let mut sheet = Sheet::new();
4249 let a = sheet.add_cell(5_i32);
4250 let result = sheet.add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)));
4251 assert!(result.is_ok());
4252 }
4253
4254 #[test]
4255 fn add_requirement_returns_distinct_ids_on_same_cell() {
4257 let mut sheet = Sheet::new();
4258 let a = sheet.add_cell(5_i32);
4259 let first = sheet
4260 .add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)))
4261 .unwrap();
4262 let result = sheet.add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x < 100)));
4263 let second = result.unwrap();
4264 assert_ne!(first, second);
4265 assert_eq!(sheet.cell_requirements(a), Some([first, second].as_slice()));
4266 }
4267
4268 #[test]
4269 fn add_requirement_allows_two_unnamed_requirements_on_the_same_cell() {
4270 let mut sheet = Sheet::new();
4271 let a = sheet.add_cell(5_i32);
4272 sheet
4273 .add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)))
4274 .unwrap();
4275 let result = sheet.add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x < 100)));
4276 assert!(result.is_ok());
4277 }
4278
4279 #[test]
4280 fn add_requirement_hard_fails_when_current_value_already_violates_it_on_a_plain_cell() {
4281 let mut sheet = Sheet::new();
4282 let a = sheet.add_cell(-5_i32);
4283 let result = sheet.add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)));
4284 assert!(matches!(result, Err(Error::InvalidRequirement)));
4285 }
4286
4287 #[test]
4288 fn add_requirement_hard_fails_when_current_value_already_violates_it_on_a_source_cell() {
4289 let mut sheet = Sheet::new();
4290 let a = sheet.add_source(-5_i32);
4291 let result = sheet.add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)));
4292 assert!(matches!(result, Err(Error::InvalidRequirement)));
4293 }
4294
4295 #[test]
4296 fn add_requirement_propagates_method_failed_when_evaluation_errors() {
4297 let mut sheet = Sheet::new();
4298 let a = sheet.add_cell(5_i32);
4299 let result = sheet.add_requirement(
4300 a,
4301 Requirement::from_fn_1(a, |_: &i32| Err(anyhow::anyhow!("boom"))),
4302 );
4303 assert!(matches!(result, Err(Error::MethodFailed { .. })));
4304 }
4305
4306 #[test]
4307 fn cell_has_the_requirement_it_was_given() {
4308 let mut sheet = Sheet::new();
4309 let a = sheet.add_cell(5_i32);
4310 let rid = sheet
4311 .add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)))
4312 .unwrap();
4313 assert_eq!(sheet.cells[a].requirements, vec![rid]);
4314 }
4315
4316 #[test]
4317 fn add_out_returns_the_cell_id_directly() {
4318 let mut sheet = Sheet::new();
4319 let width = sheet.add_cell(4_i32);
4320 let height = sheet.add_cell(5_i32);
4321 let area = sheet.add_cell(0_i32);
4322 let cell = sheet
4323 .add_out(
4324 Method::from_fn_2_1([width, height], area, |w: &i32, h: &i32| Ok(w * h)),
4325 vec![],
4326 )
4327 .unwrap();
4328 assert_eq!(cell, area);
4329 assert_eq!(sheet.cell_kind(area), Some(CellKind::Out));
4330 }
4331
4332 #[test]
4333 fn out_cell_is_referenceable_as_another_relationships_input() {
4334 let mut sheet = Sheet::new();
4335 let width = sheet.add_cell(4_i32);
4336 let height = sheet.add_cell(5_i32);
4337 let area = sheet.add_cell(0_i32);
4338 let doubled = sheet.add_cell(0_i32);
4339 sheet
4340 .add_out(
4341 Method::from_fn_2_1([width, height], area, |w: &i32, h: &i32| Ok(w * h)),
4342 vec![],
4343 )
4344 .unwrap();
4345 let result =
4346 sheet.add_relationship(vec![Method::from_fn_1_1(
4347 area,
4348 doubled,
4349 |a: &i32| Ok(a * 2),
4350 )]);
4351 assert!(result.is_ok());
4352 }
4353
4354 #[test]
4355 fn out_cell_is_referenceable_as_a_conditional_match_subject() {
4356 let mut sheet = Sheet::new();
4357 let flag = sheet.add_cell(0_i32);
4358 let derived_flag = sheet.add_cell(0_i32);
4359 sheet
4360 .add_out(
4361 Method::from_fn_1_1(flag, derived_flag, |f: &i32| Ok(*f)),
4362 vec![],
4363 )
4364 .unwrap();
4365 let result = sheet.add_conditional(
4366 MatchExpr::cell(derived_flag),
4367 Vec::<(Vec<i32>, Vec<RelationshipId>)>::new(),
4368 vec![],
4369 );
4370 assert!(result.is_ok());
4371 }
4372
4373 #[test]
4374 fn add_out_returns_invalid_cell_kind_for_a_write() {
4375 let mut sheet = Sheet::new();
4376 let width = sheet.add_cell(4_i32);
4377 let area = sheet.add_cell(0_i32);
4378 sheet
4379 .add_out(Method::from_fn_1_1(width, area, |w: &i32| Ok(*w)), vec![])
4380 .unwrap();
4381 assert!(matches!(
4382 sheet.write(area, 99_i32),
4383 Err(Error::InvalidCellKind { .. })
4384 ));
4385 }
4386
4387 #[test]
4388 fn add_out_returns_invalid_cell_kind_for_a_second_writer() {
4389 let mut sheet = Sheet::new();
4390 let width = sheet.add_cell(4_i32);
4391 let height = sheet.add_cell(5_i32);
4392 let area = sheet.add_cell(0_i32);
4393 sheet
4394 .add_out(Method::from_fn_1_1(width, area, |w: &i32| Ok(*w)), vec![])
4395 .unwrap();
4396 let result = sheet.add_out(Method::from_fn_1_1(height, area, |h: &i32| Ok(*h)), vec![]);
4397 assert!(matches!(result, Err(Error::InvalidCellKind { .. })));
4398 }
4399
4400 #[test]
4401 fn add_out_succeeds_when_target_cell_was_previously_used_only_as_an_input() {
4402 let mut sheet = Sheet::new();
4403 let a = sheet.add_cell(1_i32);
4404 let b = sheet.add_cell(2_i32);
4405 sheet
4406 .add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x))])
4407 .unwrap();
4408 let c = sheet.add_cell(0_i32);
4409 let result = sheet.add_out(Method::from_fn_1_1(a, c, |x: &i32| Ok(*x * 2)), vec![]);
4410 assert!(result.is_ok());
4411 }
4412
4413 #[test]
4414 fn add_out_with_a_requirement_that_would_fail_still_succeeds_and_propagate_reports_it() {
4415 let mut sheet = Sheet::new();
4416 let width = sheet.add_cell(4_i32);
4417 let area = sheet.add_cell(0_i32);
4418 let area_cell = sheet
4419 .add_out(
4420 Method::from_fn_1_1(width, area, |w: &i32| Ok(*w)),
4421 vec![Requirement::from_fn_1(area, |a: &i32| Ok(*a > 100))],
4422 )
4423 .unwrap();
4424 sheet.propagate().unwrap();
4425 assert!(!sheet.cell_requirements_valid(area_cell));
4426 assert_eq!(sheet.violated_requirements(area_cell).count(), 1);
4427 }
4428
4429 #[test]
4430 fn out_cells_iterates_only_out_kind_cells() {
4431 let mut sheet = Sheet::new();
4432 let a = sheet.add_cell(1_i32);
4433 let b = sheet.add_cell(0_i32);
4434 let out_id = sheet
4435 .add_out(Method::from_fn_1_1(a, b, |x: &i32| Ok(*x)), vec![])
4436 .unwrap();
4437 let ids: Vec<CellId> = sheet.out_cells().collect();
4438 assert_eq!(ids, vec![out_id]);
4439 }
4440
4441 #[test]
4442 fn add_filter_succeeds_on_a_real_out_kind_cell() {
4443 let mut sheet = Sheet::new();
4444 let width = sheet.add_cell(4_i32);
4445 let area = sheet.add_cell(0_i32);
4446 let out_cell = sheet
4447 .add_out(Method::from_fn_1_1(width, area, |w: &i32| Ok(*w)), vec![])
4448 .unwrap();
4449 let result = sheet.add_filter(out_cell, Filter::from_fn_0(|x: &i32| Ok((*x).clamp(0, 10))));
4450 assert!(result.is_ok());
4451 }
4452
4453 #[test]
4454 fn requirement_relevant_cells_covers_a_plain_cells_requirement_too() {
4455 let mut sheet = Sheet::new();
4456 let a = sheet.add_cell(5_i32);
4457 sheet
4458 .add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 0)))
4459 .unwrap();
4460 sheet.propagate().unwrap();
4461 assert!(sheet.requirement_relevant_cells().contains(&a));
4462 }
4463
4464 #[test]
4465 fn requirement_violation_cells_covers_a_plain_cells_violation_too() {
4466 let mut sheet = Sheet::new();
4472 let a = sheet.add_cell(200_i32);
4473 sheet
4474 .add_requirement(a, Requirement::from_fn_1(a, |x: &i32| Ok(*x > 100)))
4475 .unwrap();
4476 sheet.write(a, 5_i32).unwrap();
4477 sheet.propagate().unwrap();
4478 assert!(sheet.requirement_violation_cells().contains(&a));
4479 }
4480}