movable_ref/offset/
integers.rs

1use super::delta::{Nullable, Offset};
2use crate::error::{IntegerOffsetError, IntegerOffsetErrorImpl};
3use crate::pointer::unreachable::{UncheckedOptionExt, OVERFLOW_SUB};
4use core::num::*;
5
6macro_rules! impl_delta_zeroable {
7    ($($type:ty),* $(,)?) => {$(
8        unsafe impl Offset for $type {
9            type Error = IntegerOffsetError;
10
11            fn sub(a: *mut u8, b: *mut u8) -> Result<Self, Self::Error> {
12                let del = match isize::checked_sub(a as usize as _, b as usize as _) {
13                    Some(del) => del,
14                    None => return Err(IntegerOffsetError(IntegerOffsetErrorImpl::Sub(a as usize, b as usize)))
15                };
16
17                if std::mem::size_of::<Self>() < std::mem::size_of::<isize>() && (
18                    (Self::MIN as isize) > del ||
19                    (Self::MAX as isize) < del
20                )
21                {
22                    Err(IntegerOffsetError(IntegerOffsetErrorImpl::Conversion(del)))
23                } else {
24                    Ok(del as _)
25                }
26            }
27
28            unsafe fn sub_unchecked(a: *mut u8, b: *mut u8) -> Self {
29                isize::checked_sub(a as usize as _, b as usize as _).unchecked_unwrap(OVERFLOW_SUB) as _
30            }
31
32            unsafe fn add(self, a: *const u8) -> *mut u8 {
33                <*const u8>::offset(a, self as isize) as *mut u8
34            }
35        }
36
37        impl Nullable for $type {
38            const NULL: Self = 0;
39        }
40    )*};
41}
42
43impl_delta_zeroable! { i8, i16, i32, i64, i128, isize }
44
45macro_rules! impl_delta_nonzero {
46    ($($type:ident $base:ident),* $(,)?) => {$(
47        unsafe impl Offset for $type {
48            type Error = IntegerOffsetError;
49
50            fn sub(a: *mut u8, b: *mut u8) -> Result<Self, Self::Error> {
51                let del = match isize::checked_sub(a as usize as _, b as usize as _) {
52                    None => return Err(IntegerOffsetError(IntegerOffsetErrorImpl::Sub(a as usize, b as usize))),
53                    Some(0) => return Err(IntegerOffsetError(IntegerOffsetErrorImpl::InvalidNonZero)),
54                    Some(del) => del,
55                };
56
57                if std::mem::size_of::<Self>() < std::mem::size_of::<isize>() && (
58                    ($base::MIN as isize) > del ||
59                    ($base::MAX as isize) < del
60                )
61                {
62                    Err(IntegerOffsetError(IntegerOffsetErrorImpl::Conversion(del)))
63                } else {
64                    // 0 case was checked in match before hand, so this is guarenteed ot be non zero
65                    unsafe { Ok(Self::new_unchecked(del as _)) }
66                }
67            }
68
69            unsafe fn sub_unchecked(a: *mut u8, b: *mut u8) -> Self {
70                Self::new_unchecked(isize::checked_sub(a as usize as _, b as usize as _).unchecked_unwrap(OVERFLOW_SUB) as _)
71            }
72
73            unsafe fn add(self, a: *const u8) -> *mut u8 {
74                <*mut u8>::offset(a as _, self.get() as isize) as *mut u8
75            }
76        }
77    )*};
78}
79
80impl_delta_nonzero! { NonZeroI8 i8, NonZeroI16 i16, NonZeroI32 i32, NonZeroI64 i64, NonZeroI128 i128, NonZeroIsize isize }