weirflow 0.1.0

GPU-first dataflow analysis primitives for Vyre and Santh compiler pipelines.
Documentation
//! Reusable dispatch output scratch helpers.
//!
//! Compatibility wrappers sometimes adapt an older dispatch API that returns
//! `Vec<Vec<u8>>` into the allocation-aware `&mut Vec<Vec<u8>>` hot path. This
//! module keeps those adapters from discarding already-retained output slot
//! buffers on every dispatch.

/// Replace logical output slots while preserving existing slot allocations
/// where possible.
pub fn replace_outputs_preserving_slots(outputs: &mut Vec<Vec<u8>>, incoming: Vec<Vec<u8>>) {
    let mut incoming = incoming.into_iter();
    let mut reused = 0usize;
    for (slot, mut bytes) in outputs.iter_mut().zip(incoming.by_ref()) {
        replace_slot_preserving_capacity(slot, &mut bytes);
        reused += 1;
    }
    outputs.truncate(reused);
    outputs.extend(incoming);
}

#[inline]
fn replace_slot_preserving_capacity(slot: &mut Vec<u8>, bytes: &mut Vec<u8>) {
    if slot.len() == bytes.len() {
        slot.copy_from_slice(bytes);
    } else if bytes.len() <= slot.capacity() {
        slot.clear();
        slot.extend_from_slice(bytes);
    } else {
        std::mem::swap(slot, bytes);
    }
}

/// Clear every logical output slot while preserving the outer slot vector and
/// each retained slot allocation.
pub fn clear_outputs_preserving_slots(outputs: &mut [Vec<u8>]) {
    for output in outputs {
        output.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn replace_outputs_preserving_slots_reuses_existing_slot_buffers() {
        let mut outputs = vec![Vec::with_capacity(16), Vec::with_capacity(8)];
        outputs[0].extend_from_slice(&[9, 9]);
        outputs[1].extend_from_slice(&[8]);
        let outer_ptr = outputs.as_ptr() as usize;
        let first_ptr = outputs[0].as_ptr() as usize;
        let second_ptr = outputs[1].as_ptr() as usize;

        replace_outputs_preserving_slots(&mut outputs, vec![vec![1, 2, 3], vec![4, 5]]);

        assert_eq!(outputs, vec![vec![1, 2, 3], vec![4, 5]]);
        assert_eq!(outputs.as_ptr() as usize, outer_ptr);
        assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
        assert_eq!(outputs[1].as_ptr() as usize, second_ptr);
        assert!(outputs[0].capacity() >= 16);
        assert!(outputs[1].capacity() >= 8);
    }

    #[test]
    fn replace_outputs_preserving_slots_moves_new_tail_slots() {
        let mut outputs = vec![Vec::with_capacity(4)];
        let first_ptr = outputs[0].as_ptr() as usize;

        replace_outputs_preserving_slots(&mut outputs, vec![vec![1], vec![2, 3]]);

        assert_eq!(outputs, vec![vec![1], vec![2, 3]]);
        assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
    }

    #[test]
    fn replace_outputs_preserving_slots_moves_oversized_incoming_slot() {
        let mut outputs = vec![Vec::with_capacity(1)];
        let incoming = vec![vec![1, 2, 3, 4]];
        let incoming_ptr = incoming[0].as_ptr() as usize;

        replace_outputs_preserving_slots(&mut outputs, incoming);

        assert_eq!(outputs, vec![vec![1, 2, 3, 4]]);
        assert_eq!(
            outputs[0].as_ptr() as usize,
            incoming_ptr,
            "oversized incoming output should be moved into place instead of copied through a too-small retained slot"
        );
    }

    #[test]
    fn clear_outputs_preserving_slots_retains_outer_and_inner_allocations() {
        let mut outputs = vec![Vec::with_capacity(16), Vec::with_capacity(8)];
        outputs[0].extend_from_slice(&[1, 2, 3]);
        outputs[1].extend_from_slice(&[4, 5]);
        let outer_ptr = outputs.as_ptr() as usize;
        let first_ptr = outputs[0].as_ptr() as usize;
        let second_ptr = outputs[1].as_ptr() as usize;

        clear_outputs_preserving_slots(&mut outputs);

        assert_eq!(outputs.len(), 2);
        assert!(outputs.iter().all(Vec::is_empty));
        assert_eq!(outputs.as_ptr() as usize, outer_ptr);
        assert_eq!(outputs[0].as_ptr() as usize, first_ptr);
        assert_eq!(outputs[1].as_ptr() as usize, second_ptr);
        assert!(outputs[0].capacity() >= 16);
        assert!(outputs[1].capacity() >= 8);
    }
}