aqc_text_engine_core/requirement/
merge.rs1use aqc_file_engine_core::{
4 ConflictEntry, Provenance, Resolve, ResolvedRequirement, ScalarAssertion, resolve_items,
5};
6
7use super::{ResolvedTextFileRequirements, TextFileRequirements};
8
9impl TextFileRequirements {
10 #[allow(
16 clippy::needless_pass_by_value,
17 reason = "merged_reconcile passes owned typed requirements to every engine merge function."
18 )]
19 pub fn merge(
20 reqs: Vec<(Provenance, Self)>,
21 ) -> Result<ResolvedTextFileRequirements, Vec<ConflictEntry>> {
22 let mut conflicts = Vec::new();
23 let exact_contents = resolve_optional_scalar(
24 "exact_contents",
25 &reqs,
26 |req| req.exact_contents.clone(),
27 &mut conflicts,
28 );
29 let contents = resolve_items(
30 "contents",
31 reqs.iter()
32 .map(|(prov, req)| (prov.clone(), req.contents.clone()))
33 .collect(),
34 &mut conflicts,
35 );
36 let resolved = ResolvedTextFileRequirements {
37 exact_contents,
38 contents,
39 };
40 if conflicts.is_empty() {
41 Ok(resolved)
42 } else {
43 Err(conflicts)
44 }
45 }
46}
47
48fn resolve_optional_scalar<T>(
50 key: &str,
51 items: &[(Provenance, TextFileRequirements)],
52 get: impl Fn(&TextFileRequirements) -> Option<ScalarAssertion<T>>,
53 conflicts: &mut Vec<ConflictEntry>,
54) -> Option<ResolvedRequirement<ScalarAssertion<T>, ScalarAssertion<T>>>
55where
56 T: aqc_file_engine_core::ScalarValue,
57{
58 let assertions = items
59 .iter()
60 .filter_map(|(prov, req)| get(req).map(|assertion| (prov.clone(), assertion)))
61 .collect::<Vec<_>>();
62 if assertions.is_empty() {
63 None
64 } else {
65 ScalarAssertion::<T>::resolve(key, assertions, conflicts)
66 }
67}