#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Edge {
pub size: Option<u16>,
pub fraction: u16,
pub min_size: u16,
}
impl Default for Edge {
fn default() -> Self {
Self {
size: None,
fraction: 1,
min_size: 0,
}
}
}
pub fn layout_resolve_1d(total: u16, edges: &[Edge]) -> Vec<u16> {
if edges.is_empty() {
return Vec::new();
}
let mut sizes: Vec<Option<u16>> = edges.iter().map(|e| e.size).collect();
if sizes.iter().all(|s| s.is_some()) {
return sizes.iter().map(|s| s.unwrap()).collect();
}
let mut flexible: Vec<(usize, u16, u16)> = Vec::new();
for (i, (sz, edge)) in sizes.iter().zip(edges.iter()).enumerate() {
if sz.is_none() {
flexible.push((i, edge.fraction.max(1), edge.min_size));
}
}
let fixed_sum: u32 = sizes.iter().map(|s| s.unwrap_or(0) as u32).sum();
let remaining_signed = total as i32 - fixed_sum as i32;
if remaining_signed <= 0 {
return sizes
.iter()
.zip(edges.iter())
.map(|(sz, edge)| match sz {
Some(s) => *s,
None => edge.min_size.max(1),
})
.collect();
}
let mut remaining = remaining_signed as u64;
let mut total_fraction: u64 = flexible.iter().map(|&(_, f, _)| f as u64).sum();
loop {
if flexible.is_empty() || total_fraction == 0 {
break;
}
let mut fixed_one = false;
for idx in 0..flexible.len() {
let (edge_idx, fraction, min_size) = flexible[idx];
let lhs = remaining * (fraction as u64);
let rhs = (min_size as u64) * total_fraction;
if min_size > 0 && lhs < rhs {
sizes[edge_idx] = Some(min_size);
remaining = remaining.saturating_sub(min_size as u64);
total_fraction -= fraction as u64;
flexible.remove(idx);
fixed_one = true;
break;
}
}
if !fixed_one {
if total_fraction > 0 {
let mut rem_num: u64 = 0;
for &(edge_idx, fraction, _) in &flexible {
let raw = remaining * fraction as u64 + rem_num;
sizes[edge_idx] = Some((raw / total_fraction) as u16);
rem_num = raw % total_fraction;
}
}
break;
}
}
sizes.iter().map(|s| s.unwrap_or(0)).collect()
}