1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use core::slice;

pub fn bytes_between<T>(ptr1: *const T, ptr2: *const T) -> usize {
    if ptr2 > ptr1 {
        ptr2 as usize - ptr1 as usize
    } else {
        ptr1 as usize - ptr2 as usize
    }
}

pub trait Align {
    fn down(value: Self, round: usize) -> Self;
    fn up(value: Self, round: usize) -> Self;
    fn range(base: Self, len: usize, round: usize) -> (Self, usize);
    fn is_aligned(value: Self, round: usize) -> bool;
}

impl Align for usize {
    fn down(value: usize, round: usize) -> usize {
        value & !(round - 1)
    }

    fn up(value: usize, round: usize) -> usize {
        Align::down(value + round - 1, round)
    }

    fn range(base: usize, len: usize, round: usize) -> (usize, usize) {
        let end = Align::up(base + len, round);
        let base = Align::down(base, round);
        (base, end - base)
    }

    fn is_aligned(value: Self, round: usize) -> bool {
        value & (round - 1) == 0
    }
}

impl<T> Align for *const T {
    fn down(value: *const T, round: usize) -> *const T {
        Align::down(value as usize, round) as *const T
    }

    fn up(value: *const T, round: usize) -> *const T {
        Align::up(value as usize, round) as *const T
    }

    fn range(base: *const T, len: usize, round: usize) -> (*const T, usize) {
        let (base, len) = Align::range(base as usize, len, round);
        (base as *const T, len)
    }

    fn is_aligned(value: *const T, round: usize) -> bool {
        Align::is_aligned(value as usize, round)
    }
}

pub unsafe fn align_slice<T>(slice: &[T], round: usize) -> &[T] {
    let (ptr, len) = (slice.as_ptr(), slice.len());
    let (ptr, len) = Align::range(ptr, len, round);
    slice::from_raw_parts(ptr, len)
}

pub unsafe fn align_slice_mut<T>(slice: &mut [T], round: usize) -> &mut [T] {
    let (ptr, len) = (slice.as_mut_ptr(), slice.len());
    let (ptr, len) = Align::range(ptr, len, round);
    slice::from_raw_parts_mut(ptr, len)
}

impl<T> Align for *mut T {
    fn down(value: *mut T, round: usize) -> *mut T {
        Align::down(value as usize, round) as *mut T
    }

    fn up(value: *mut T, round: usize) -> *mut T {
        Align::up(value as usize, round) as *mut T
    }

    fn range(base: *mut T, len: usize, round: usize) -> (*mut T, usize) {
        let (base, len) = Align::range(base as usize, len, round);
        (base as *mut T, len)
    }

    fn is_aligned(value: *mut T, round: usize) -> bool {
        Align::is_aligned(value as usize, round)
    }
}

#[cfg(feature = "test")]
pub mod test {
    use super::*;

    test! {
        fn can_align_down() {
            let ptr = 0x1234 as *const u8;
            let expected_ptr = 0x1000 as *const u8;
            assert_eq!(expected_ptr, Align::down(ptr, 0x1000));
            assert_eq!(expected_ptr, Align::down(expected_ptr, 0x1000));
        }

        fn can_align_up() {
            let ptr = 0x1234 as *const u8;
            let expected_ptr = 0x2000 as *const u8;
            assert_eq!(expected_ptr, Align::up(ptr, 0x1000));
            assert_eq!(expected_ptr, Align::up(expected_ptr, 0x1000));
        }

        fn can_align_range() {
            let base = 0x1234 as *const u8;
            let len = 0x5678;
            let expected_base = 0x1000 as *const u8;
            let expected_len = 0x6000;
            assert_eq!((expected_base, expected_len), Align::range(base, len, 0x1000));
            assert_eq!((expected_base, expected_len), Align::range(expected_base, expected_len, 0x1000));
        }
    }
}