ruda-runtime 0.1.33

Ruda portable host runtime.
use alloc::vec::Vec;
use core::ops::Range;
use smallvec::SmallVec;

use super::{ErrorGraph, FailureId};

type Ranges = SmallVec<[Range<u64>; 1]>;

#[derive(Debug, Default)]
pub(crate) struct Taint {
    entries: SmallVec<[Tainted; 1]>,
}

#[derive(Debug)]
struct Tainted {
    failure: ErrorGraph,
    ranges: Ranges,
    unallocated: bool,
}

impl Drop for Tainted {
    fn drop(&mut self) {
        self.failure.untag();
    }
}

impl Taint {
    pub(crate) fn claim(&mut self, range: Range<u64>, failure: ErrorGraph) {
        if range.is_empty() {
            return;
        }
        self.entries.retain_mut(|entry| {
            if entry.failure.id() != failure.id() {
                subtract(&mut entry.ranges, &range);
            }
            entry.unallocated || !entry.ranges.is_empty()
        });
        if let Some(entry) = self.entries.iter_mut().find(|entry| entry.failure.id() == failure.id()) {
            add(&mut entry.ranges, range);
        } else {
            failure.tag();
            self.entries.push(Tainted { failure, ranges: Ranges::from_buf([range]), unallocated: false });
        }
    }

    pub(crate) fn claim_unallocated(&mut self, failure: ErrorGraph) {
        self.entries.clear();
        failure.tag();
        self.entries.push(Tainted { failure, ranges: Ranges::new(), unallocated: true });
    }

    pub(crate) fn clear_unallocated(&mut self) {
        self.entries.retain_mut(|entry| {
            entry.unallocated = false;
            !entry.ranges.is_empty()
        });
    }

    pub(crate) fn failures(&self, range: Range<u64>) -> Vec<ErrorGraph> {
        self.entries.iter()
            .filter(|entry| entry.unallocated || entry.ranges.iter().any(|held| overlaps(held, &range)))
            .map(|entry| entry.failure.clone())
            .collect()
    }

    pub(crate) fn written(&mut self, range: Range<u64>) {
        if range.is_empty() {
            return;
        }
        self.entries.retain_mut(|entry| {
            subtract(&mut entry.ranges, &range);
            entry.unallocated || !entry.ranges.is_empty()
        });
    }

    pub(crate) fn release(&mut self, range: Range<u64>, failure: FailureId) {
        self.entries.retain_mut(|entry| {
            if entry.failure.id() == failure {
                subtract(&mut entry.ranges, &range);
                entry.unallocated = false;
            }
            entry.unallocated || !entry.ranges.is_empty()
        });
    }
}

fn overlaps(a: &Range<u64>, b: &Range<u64>) -> bool {
    a.start.max(b.start) < a.end.min(b.end)
}

fn add(ranges: &mut Ranges, mut new: Range<u64>) {
    ranges.retain(|held| {
        let fuses = held.start <= new.end && new.start <= held.end;
        if fuses {
            new.start = new.start.min(held.start);
            new.end = new.end.max(held.end);
        }
        !fuses
    });
    let at = ranges.iter().position(|held| new.end < held.start).unwrap_or(ranges.len());
    ranges.insert(at, new);
}

fn subtract(ranges: &mut Ranges, cut: &Range<u64>) {
    let mut index = 0;
    while index < ranges.len() {
        let held = ranges[index].clone();
        if !overlaps(&held, cut) {
            index += 1;
            continue;
        }
        let left = held.start..cut.start.min(held.end);
        let right = cut.end.max(held.start)..held.end;
        match (left.is_empty(), right.is_empty()) {
            (true, true) => { ranges.remove(index); }
            (false, true) => { ranges[index] = left; index += 1; }
            (true, false) => { ranges[index] = right; index += 1; }
            (false, false) => {
                ranges[index] = left;
                ranges.insert(index + 1, right);
                index += 2;
            }
        }
    }
}