use super::{
DiscoveredMutationSite, DiscoveryDisposition, DiscoveryEntry, DiscoveryLoweringRefusal,
EvaluationSurface, MappedUnpermittedCause, MutationDiscoveryReading, MutationPoint,
MutationPolicy, MutationSurfaceLowering, OwnerClaimMapping,
};
use crate::descriptor::MutationPointRef;
use std::collections::BTreeSet;
pub fn lower_discoveries(
policy: &MutationPolicy,
sites: Vec<DiscoveredMutationSite>,
) -> Result<MutationSurfaceLowering, DiscoveryLoweringRefusal> {
let mut seen: BTreeSet<MutationPointRef> = BTreeSet::new();
for (at, site) in sites.iter().enumerate() {
if !seen.insert(site.identity()) {
return Err(DiscoveryLoweringRefusal::DuplicateSite {
at,
point: site.identity(),
});
}
}
let mut entries = Vec::with_capacity(sites.len());
let mut points = Vec::new();
for site in sites {
let disposition = admit(policy, &site, &mut points);
entries.push(DiscoveryEntry::recorded(site, disposition));
}
let discovery = MutationDiscoveryReading::recorded(policy, entries);
let surface = EvaluationSurface::admitted(policy, points);
Ok(MutationSurfaceLowering::lowered(discovery, surface))
}
fn admit(
policy: &MutationPolicy,
site: &DiscoveredMutationSite,
points: &mut Vec<MutationPoint>,
) -> DiscoveryDisposition {
let OwnerClaimMapping::Mapped(claim) = site.mapping() else {
return DiscoveryDisposition::OwnerUnmapped;
};
let Some(permission) = policy.permission(claim) else {
return DiscoveryDisposition::MappedUnpermitted {
cause: MappedUnpermittedCause::Claim(claim),
};
};
let outside = site
.alternatives()
.iter()
.enumerate()
.find(|(_, alternative)| !permission.admits(alternative.family()));
if let Some((at, alternative)) = outside {
return DiscoveryDisposition::MappedUnpermitted {
cause: MappedUnpermittedCause::Family {
at,
family: alternative.family(),
},
};
}
let point = MutationPoint::admitted(policy, claim, site.clone());
let identity = point.identity();
points.push(point);
DiscoveryDisposition::Mapped { point: identity }
}