use super::super::Version;
use super::types::{Bound, BoundSet};
pub(super) fn is_bound_set_satisfiable(bs: &BoundSet) -> bool {
if bs.bounds.iter().any(|b| matches!(b, Bound::None)) {
return false;
}
let mut lower: Option<(&Version, bool)> = None; let mut upper: Option<(&Version, bool)> = None;
for bound in &bs.bounds {
match bound {
Bound::Any | Bound::Ne(_) | Bound::Compatible(_) => {}
Bound::None => return false,
Bound::Ge(v) => match lower {
None => lower = Some((v, true)),
Some((lv, linc)) => {
if v > lv || (v == lv && !linc) {
lower = Some((v, true));
}
}
},
Bound::Gt(v) => match lower {
None => lower = Some((v, false)),
Some((lv, _)) => {
if v >= lv {
lower = Some((v, false));
}
}
},
Bound::Le(v) => match upper {
None => upper = Some((v, true)),
Some((uv, uinc)) => {
if v < uv || (v == uv && !uinc) {
upper = Some((v, true));
}
}
},
Bound::Lt(v) => match upper {
None => upper = Some((v, false)),
Some((uv, _)) => {
if v <= uv {
upper = Some((v, false));
}
}
},
Bound::Eq(v) => {
match lower {
None => lower = Some((v, true)),
Some((lv, linc)) => {
if v > lv || (v == lv && !linc) {
lower = Some((v, true));
} else if v < lv {
return false;
}
}
}
match upper {
None => upper = Some((v, true)),
Some((uv, uinc)) => {
if v < uv || (v == uv && !uinc) {
upper = Some((v, true));
} else if v > uv {
return false;
}
}
}
}
}
}
if let (Some((lv, linc)), Some((uv, uinc))) = (lower, upper) {
match lv.cmp(uv) {
std::cmp::Ordering::Greater => return false,
std::cmp::Ordering::Equal => {
if !linc || !uinc {
return false;
}
}
std::cmp::Ordering::Less => {}
}
}
true
}
pub(super) fn bound_sets_intersect(a: &BoundSet, b: &BoundSet) -> bool {
let a_any = a.bounds.iter().all(|bnd| matches!(bnd, Bound::Any));
let b_any = b.bounds.iter().all(|bnd| matches!(bnd, Bound::Any));
if a_any || b_any {
return true;
}
let combined_bounds: Vec<&Bound> = a.bounds.iter().chain(b.bounds.iter()).collect();
let eq_versions: Vec<&Version> = combined_bounds
.iter()
.filter_map(|b| if let Bound::Eq(v) = b { Some(v) } else { None })
.collect();
if eq_versions.len() > 1 {
let first = eq_versions[0];
if eq_versions.iter().any(|v| *v != first) {
return false;
}
}
for eq_v in &eq_versions {
for bound in &combined_bounds {
match bound {
Bound::Ge(w) if *eq_v < w => return false,
Bound::Gt(w) if *eq_v <= w => return false,
Bound::Le(w) if *eq_v > w => return false,
Bound::Lt(w) if *eq_v >= w => return false,
_ => {}
}
}
}
let mut lower: Option<(&Version, bool)> = None; let mut upper: Option<(&Version, bool)> = None;
for bound in &combined_bounds {
match bound {
Bound::Ge(v) => match lower {
None => lower = Some((v, true)),
Some((lv, linc)) => {
if v > lv || (v == lv && !linc) {
lower = Some((v, true));
}
}
},
Bound::Gt(v) => match lower {
None => lower = Some((v, false)),
Some((lv, _linc)) => {
if v >= lv {
lower = Some((v, false));
}
}
},
Bound::Le(v) => match upper {
None => upper = Some((v, true)),
Some((uv, uinc)) => {
if v < uv || (v == uv && !uinc) {
upper = Some((v, true));
}
}
},
Bound::Lt(v) => match upper {
None => upper = Some((v, false)),
Some((uv, _uinc)) => {
if v <= uv {
upper = Some((v, false));
}
}
},
_ => {}
}
}
if let (Some((lv, linc)), Some((uv, uinc))) = (lower, upper) {
match lv.cmp(uv) {
std::cmp::Ordering::Greater => return false,
std::cmp::Ordering::Equal => {
if !linc || !uinc {
return false;
}
}
std::cmp::Ordering::Less => {} }
}
true
}