macroassembler 1.0.5

A library for writing portable x86-64/riscv64/aarch64 assembly code in Rust
Documentation
pub mod code_ptr;
pub mod executable_memory_handle;

use core::ops::*;
use num_traits::{FromPrimitive, NumOps, One, ToPrimitive, Zero};
use std::mem::size_of;
pub fn is_power_of_two<
    T: BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Not<Output = T>
        + PartialEq
        + Copy
        + Zero
        + One
        + Sub<Output = T>,
>(
    x: T,
) -> bool {
    (x & (x - T::one())) == T::zero() && (x != T::zero())
}

pub fn shift_for_power_of_two<
    T: Shr<T, Output = T>
        + Copy
        + Eq
        + One
        + Zero
        + Not<Output = T>
        + BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Sub<Output = T>
        + PartialOrd,
>(
    mut x: T,
) -> i32 {
    assert!(is_power_of_two(x));
    let mut num_shifts = 0;
    while x > T::one() {
        num_shifts += 1;
        x = x >> T::one();
    }
    num_shifts
}

pub fn is_aligned<
    T: BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Not<Output = T>
        + PartialEq
        + Copy
        + Zero
        + One
        + Sub<Output = T>
        + ToPrimitive,
>(
    x: T,
    alignment: usize,
    offset: usize,
) -> bool {
    assert!(is_power_of_two(alignment));
    assert!(offset < alignment);
    let x = x.to_isize();
    let x = match x {
        Some(x) => x,
        _ => return false,
    };
    (x & (alignment as isize - 1)) == offset as isize
}

pub fn is_aligned_ptr<
    T,
    U: BitOr<U, Output = U> + BitAnd<U, Output = U> + Not<Output = U> + PartialEq + Copy + Zero + One,
>(
    x: *const T,
    alignment: usize,
    offset: usize,
) -> bool {
    is_aligned(x as usize, alignment, offset)
}

pub fn round_down<
    T: BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Not<Output = T>
        + Copy
        + FromPrimitive
        + ToPrimitive,
>(
    x: T,
    alignment: isize,
) -> T {
    assert!(is_power_of_two(alignment));
    T::from_isize(x.to_isize().unwrap() & -alignment).unwrap()
}

pub fn round_down_unchecked<
    T: BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Not<Output = T>
        + Copy
        + FromPrimitive
        + ToPrimitive,
>(
    x: T,
    alignment: isize,
) -> T {
    T::from_isize(x.to_isize().unwrap() & -alignment).unwrap()
}

pub fn round_down_ptr<T, U: BitOr<U, Output = U> + Not<Output = U> + Copy>(
    x: *const T,
    alignment: isize,
) -> *const T {
    round_down(x as usize, alignment) as *const T
}

pub fn round_up<
    T: One
        + NumOps
        + BitOr<T, Output = T>
        + Not<Output = T>
        + Copy
        + BitAnd<T, Output = T>
        + FromPrimitive
        + ToPrimitive,
>(
    x: T,
    alignment: usize,
    offset: usize,
) -> T {
    assert!(offset < alignment);
    round_down(
        x + T::from_usize(alignment).unwrap() - T::one() + T::from_usize(offset).unwrap(),
        alignment as _,
    ) - T::from_usize(offset).unwrap()
}

pub fn round_up_unchecked<
    T: One
        + NumOps
        + BitOr<T, Output = T>
        + Not<Output = T>
        + Copy
        + BitAnd<T, Output = T>
        + FromPrimitive
        + ToPrimitive,
>(
    x: T,
    alignment: usize,
    offset: usize,
) -> T {
    round_down_unchecked(
        x + T::from_usize(alignment).unwrap() - T::one() + T::from_usize(offset).unwrap(),
        alignment as _,
    ) - T::from_usize(offset).unwrap()
}

pub fn round_up_ptr<T, U: BitOr<U, Output = U> + Not<Output = U> + Copy>(
    x: *const T,
    alignment: usize,
    offset: usize,
) -> *const T {
    round_up(x as usize, alignment, offset) as *const T
}

pub fn round_up_to_power_of_two(x: usize) -> usize {
    let mut x = x - 1;
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >> 16);
    #[cfg(target_pointer_width = "64")]
    {
        x = x | (x >> 32);
    }

    x + 1
}

pub fn round_up_usize(x: usize, alignment: usize, offset: usize) -> usize {
    round_up_unchecked(x, alignment, offset)
}

pub const fn log2i_graceful(value: usize) -> isize {
    if value == 0 {
        return -1;
    }

    let bits = size_of::<usize>() * 8;

    bits as isize - value.leading_zeros() as isize - 1
}

pub fn has_one_bit_set<
    T: Copy
        + Eq
        + One
        + Zero
        + Not<Output = T>
        + BitOr<T, Output = T>
        + BitAnd<T, Output = T>
        + Sub<Output = T>
        + PartialOrd
        + PartialEq,
>(
    value: T,
) -> bool {
    // !((value - 1) & value) && value
    (value & (value - T::one())) == T::zero() && (value != T::zero())
}