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 #[must_use]
11 #[allow(
12 clippy::needless_pass_by_value,
13 reason = "merged_reconcile passes owned typed requirements to every engine merge function."
14 )]
15 pub fn merge(
16 reqs: Vec<(Provenance, Self)>,
17 ) -> (ResolvedTextFileRequirements, Vec<ConflictEntry>) {
18 let mut conflicts = Vec::new();
19 let exact_contents = resolve_optional_scalar(
20 "exact_contents",
21 &reqs,
22 |req| req.exact_contents.clone(),
23 &mut conflicts,
24 );
25 let contents = resolve_items(
26 "contents",
27 reqs.iter()
28 .map(|(prov, req)| (prov.clone(), req.contents.clone()))
29 .collect(),
30 &mut conflicts,
31 );
32 (
33 ResolvedTextFileRequirements {
34 exact_contents,
35 contents,
36 },
37 conflicts,
38 )
39 }
40}
41
42fn resolve_optional_scalar<T>(
44 key: &str,
45 items: &[(Provenance, TextFileRequirements)],
46 get: impl Fn(&TextFileRequirements) -> Option<ScalarAssertion<T>>,
47 conflicts: &mut Vec<ConflictEntry>,
48) -> Option<ResolvedRequirement<ScalarAssertion<T>, ScalarAssertion<T>>>
49where
50 T: aqc_file_engine_core::ScalarValue,
51{
52 let assertions = items
53 .iter()
54 .filter_map(|(prov, req)| get(req).map(|assertion| (prov.clone(), assertion)))
55 .collect::<Vec<_>>();
56 if assertions.is_empty() {
57 None
58 } else {
59 ScalarAssertion::<T>::resolve(key, assertions, conflicts)
60 }
61}