nonymous 0.7.0

DNS protocol and algorithm library
Documentation
macro_rules! swap {
    ($xs:expr, $i:expr, $j:expr) => {
        let scratch = $xs[$i];
        $xs[$i] = $xs[$j];
        $xs[$j] = scratch;
    };
}

macro_rules! up {
    ($xs:expr, $xn:expr, $cmp:expr, $i:expr) => {{
        use ::core::cmp::Ordering;

        use $crate::core::r#const::heap;

        let mut i = $i;
        while let Some(j) = heap::parent(i) {
            if let Ordering::Less = $cmp($xs[j], $xs[i]) {
                swap!($xs, i, j);
                i = j;
            } else {
                break;
            }
        }

        i
    }};
}

macro_rules! down {
    ($xs:expr, $xn:expr, $cmp:expr, $i:expr) => {{
        use ::core::cmp::Ordering;

        use $crate::core::r#const::heap;

        let mut i = $i;
        loop {
            let j = match (heap::left(i, $xn), heap::right(i, $xn)) {
                (Some(p), Some(q)) => match $cmp($xs[p], $xs[q]) {
                    Ordering::Less => Some(q),
                    _ => Some(p),
                },
                (Some(p), _) => Some(p),
                (_, Some(q)) => Some(q),
                (_, _) => break,
            };
            match j {
                Some(j) => match $cmp($xs[i], $xs[j]) {
                    Ordering::Less => {
                        swap!($xs, i, j);
                        i = j;
                    }
                    _ => break,
                },
                _ => break,
            }
        }

        i
    }};
}

macro_rules! insert {
    ($xs:expr, $xn:expr, $cmp:expr, $x:expr) => {{
        $xs[$xn] = $x;
        $xn += 1;

        up!($xs, $xn, $cmp, $xn - 1)
    }};
}

macro_rules! drain {
    ($xs:expr, $xn:expr, $cmp:expr) => {{
        let mut len = $xn;
        while len > 1 {
            len -= 1;
            swap!($xs, 0, len);
            down!($xs, len, $cmp, 0);
        }
    }};
}

pub const fn parent(i: usize) -> Option<usize> {
    if i < 1 {
        return None;
    }

    Some((i - 1) / 2)
}

pub const fn left(i: usize, len: usize) -> Option<usize> {
    let result = i * 2 + 1;

    if result < len {
        Some(result)
    } else {
        None
    }
}

pub const fn right(i: usize, len: usize) -> Option<usize> {
    let result = i * 2 + 2;

    if result < len {
        Some(result)
    } else {
        None
    }
}

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

    #[test]
    pub fn insert() {
        let mut xs = [11, 5, 8, 3, 4, /* empty */ 0, 0, 0];
        let mut xn = 5;
        assert_eq!(insert!(xs, xn, cmp_k, 15), 0);
        assert_eq!(xs[..xn], [15, 5, 11, 3, 4, 8]);
        assert_eq!(insert!(xs, xn, cmp_k, 12), 2);
        assert_eq!(xs[..xn], [15, 5, 12, 3, 4, 8, 11]);
    }

    #[test]
    pub fn drain() {
        let mut xs = [11, 5, 8, 3, 4, /* empty */ 0, 0, 0];
        let xn = 5;
        drain!(xs, xn, cmp_k);
        assert_eq!(xs[..xn], [3, 4, 5, 8, 11]);
        assert_eq!(xn, 5); // should be 0 tbh
    }
}