Skip to main content

ax_memory_addr/
addr.rs

1use core::cmp::Ord;
2
3/// A trait for memory address types.
4///
5/// Memory address types here include both physical and virtual addresses, as
6/// well as any other similar types like guest physical addresses in a
7/// hypervisor.
8///
9/// This trait is automatically implemented for any type that is `Copy`,
10/// `From<usize>`, `Into<usize>`, and `Ord`, providing a set of utility methods
11/// for address alignment and arithmetic.
12pub trait MemoryAddr:
13    // The address type should be trivially copyable. This implies `Clone`.
14    Copy
15    // The address type should be convertible to and from `usize`.
16    + From<usize>
17    + Into<usize>
18    // The address type should be comparable.
19    + Ord
20{
21    // No required methods for now. Following are some utility methods.
22
23    //
24    // This section contains utility methods for address alignment.
25    //
26
27    /// Aligns the address downwards to the given alignment.
28    #[inline]
29    #[must_use = "this returns a new address, without modifying the original"]
30    fn align_down<U>(self, align: U) -> Self
31    where
32        U: Into<usize>,
33    {
34        Self::from(crate::align_down(self.into(), align.into()))
35    }
36
37    /// Aligns the address upwards to the given alignment.
38    #[inline]
39    #[must_use = "this returns a new address, without modifying the original"]
40    fn align_up<U>(self, align: U) -> Self
41    where
42        U: Into<usize>,
43    {
44        Self::from(crate::align_up(self.into(), align.into()))
45    }
46
47    /// Returns the offset of the address within the given alignment.
48    #[inline]
49    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
50    fn align_offset<U>(self, align: U) -> usize
51    where
52        U: Into<usize>,
53    {
54        crate::align_offset(self.into(), align.into())
55    }
56
57    /// Checks whether the address has the demanded alignment.
58    #[inline]
59    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
60    fn is_aligned<U>(self, align: U) -> bool
61    where
62        U: Into<usize>,
63    {
64        crate::is_aligned(self.into(), align.into())
65    }
66
67    /// Aligns the address downwards to 4096 (bytes).
68    #[inline]
69    #[must_use = "this returns a new address, without modifying the original"]
70    fn align_down_4k(self) -> Self {
71        Self::from(crate::align_down(self.into(), crate::PAGE_SIZE_4K))
72    }
73
74    /// Aligns the address upwards to 4096 (bytes).
75    #[inline]
76    #[must_use = "this returns a new address, without modifying the original"]
77    fn align_up_4k(self) -> Self {
78        Self::from(crate::align_up(self.into(), crate::PAGE_SIZE_4K))
79    }
80
81    /// Returns the offset of the address within a 4K-sized page.
82    #[inline]
83    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
84    fn align_offset_4k(self) -> usize {
85        crate::align_offset(self.into(), crate::PAGE_SIZE_4K)
86    }
87
88    /// Checks whether the address is 4K-aligned.
89    #[inline]
90    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
91    fn is_aligned_4k(self) -> bool {
92        crate::is_aligned(self.into(), crate::PAGE_SIZE_4K)
93    }
94
95    //
96    // This section contains utility methods for address arithmetic.
97    //
98
99    /// Adds a given offset to the address to get a new address.
100    /// 
101    /// # Panics
102    /// 
103    /// Panics if the result overflows.
104    #[inline]
105    #[must_use = "this returns a new address, without modifying the original"]
106    fn offset(self, offset: isize) -> Self {
107        // todo: use `strict_add_signed` when it's stable.
108        Self::from(usize::checked_add_signed(self.into(), offset).expect("overflow in `MemoryAddr::offset`"))
109    }
110
111    /// Adds a given offset to the address to get a new address.
112    /// 
113    /// Unlike `offset`, this method always wraps around on overflow.
114    #[inline]
115    #[must_use = "this returns a new address, without modifying the original"]
116    fn wrapping_offset(self, offset: isize) -> Self {
117        Self::from(usize::wrapping_add_signed(self.into(), offset))
118    }
119
120    /// Gets the distance between two addresses.
121    /// 
122    /// # Panics
123    /// 
124    /// Panics if the result is not representable by `isize`.
125    #[inline]
126    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
127    fn offset_from(self, base: Self) -> isize {
128        let result = usize::wrapping_sub(self.into(), base.into()) as isize;
129        if (result > 0) ^ (base < self) {
130            // The result has overflowed.
131            panic!("overflow in `MemoryAddr::offset_from`");
132        } else {
133            result
134        }
135    }
136
137    /// Adds a given **unsigned** offset to the address to get a new address.
138    /// 
139    /// This method is similar to `offset`, but it takes an unsigned offset.
140    /// 
141    /// # Panics
142    /// 
143    /// Panics if the result overflows.
144    #[inline]
145    #[must_use = "this returns a new address, without modifying the original"]
146    fn add(self, rhs: usize) -> Self {
147        Self::from(usize::checked_add(self.into(), rhs).expect("overflow in `MemoryAddr::add`"))
148    }
149
150    /// Adds a given **unsigned** offset to the address to get a new address.
151    /// 
152    /// Unlike `add`, this method always wraps around on overflow.
153    #[inline]
154    #[must_use = "this returns a new address, without modifying the original"]
155    fn wrapping_add(self, rhs: usize) -> Self {
156        Self::from(usize::wrapping_add(self.into(), rhs))
157    }
158
159    /// Adds a given **unsigned** offset to the address to get a new address.
160    /// 
161    /// Unlike `add`, this method returns a tuple of the new address and a boolean indicating
162    /// whether the addition has overflowed.
163    #[inline]
164    #[must_use = "this returns a new address, without modifying the original"]
165    fn overflowing_add(self, rhs: usize) -> (Self, bool) {
166        let (result, overflow) = self.into().overflowing_add(rhs);
167        (Self::from(result), overflow)
168    }
169
170    /// Adds a given **unsigned** offset to the address to get a new address.
171    /// 
172    /// Unlike `add`, this method returns `None` on overflow.
173    #[inline]
174    #[must_use = "this returns a new address, without modifying the original"]
175    fn checked_add(self, rhs: usize) -> Option<Self> {
176        usize::checked_add(self.into(), rhs).map(Self::from)
177    }
178
179    /// Subtracts a given **unsigned** offset from the address to get a new address.
180    /// 
181    /// This method is similar to `offset(-rhs)`, but it takes an unsigned offset. 
182    /// 
183    /// # Panics
184    /// 
185    /// Panics if the result overflows.
186    #[inline]
187    #[must_use = "this returns a new address, without modifying the original"]
188    fn sub(self, rhs: usize) -> Self {
189        Self::from(usize::checked_sub(self.into(), rhs).expect("overflow in `MemoryAddr::sub`"))
190    }
191
192    /// Subtracts a given **unsigned** offset from the address to get a new address.
193    /// 
194    /// Unlike `sub`, this method always wraps around on overflowed.
195    #[inline]
196    #[must_use = "this returns a new address, without modifying the original"]
197    fn wrapping_sub(self, rhs: usize) -> Self {
198        Self::from(usize::wrapping_sub(self.into(), rhs))
199    }
200
201    /// Subtracts a given **unsigned** offset from the address to get a new address.
202    /// 
203    /// Unlike `sub`, this method returns a tuple of the new address and a boolean indicating
204    /// whether the subtraction has overflowed.
205    #[inline]
206    #[must_use = "this returns a new address, without modifying the original"]
207    fn overflowing_sub(self, rhs: usize) -> (Self, bool) {
208        let (result, overflow) = self.into().overflowing_sub(rhs);
209        (Self::from(result), overflow)
210    }
211
212    /// Subtracts a given **unsigned** offset from the address to get a new address.
213    /// 
214    /// Unlike `sub`, this method returns `None` on overflow.
215    #[inline]
216    #[must_use = "this returns a new address, without modifying the original"]
217    fn checked_sub(self, rhs: usize) -> Option<Self> {
218        usize::checked_sub(self.into(), rhs).map(Self::from)
219    }
220
221    /// Subtracts another address from the address to get the offset between them.
222    /// 
223    /// # Panics
224    /// 
225    /// Panics if the result overflows.
226    #[inline]
227    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
228    fn sub_addr(self, rhs: Self) -> usize {
229        usize::checked_sub(self.into(), rhs.into()).expect("overflow in `MemoryAddr::sub_addr`")
230    }
231
232    /// Subtracts another address from the address to get the offset between them.
233    /// 
234    /// Unlike `sub_addr`, this method always wraps around on overflow.
235    #[inline]
236    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
237    fn wrapping_sub_addr(self, rhs: Self) -> usize {
238        usize::wrapping_sub(self.into(), rhs.into())
239    }
240
241    /// Subtracts another address from the address to get the offset between them.
242    /// 
243    /// Unlike `sub_addr`, this method returns a tuple of the offset and a boolean indicating
244    /// whether the subtraction has overflowed.
245    #[inline]
246    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
247    fn overflowing_sub_addr(self, rhs: Self) -> (usize, bool) {
248        usize::overflowing_sub(self.into(), rhs.into())
249    }
250
251    /// Subtracts another address from the address to get the offset between them.
252    /// 
253    /// Unlike `sub_addr`, this method returns `None` on overflow.
254    #[inline]
255    #[must_use = "this function has no side effects, so it can be removed if the return value is not used"]
256    fn checked_sub_addr(self, rhs: Self) -> Option<usize> {
257        usize::checked_sub(self.into(), rhs.into())
258    }
259}
260
261/// Implement the `MemoryAddr` trait for any type that is `Copy`, `From<usize>`,
262/// `Into<usize>`, and `Ord`.
263impl<T> MemoryAddr for T where T: Copy + From<usize> + Into<usize> + Ord {}
264
265/// Creates a new address type by wrapping an `usize`.
266///
267/// For each `$vis type $name;`, this macro generates the following items:
268/// - Definition of the new address type `$name`, which contains a single
269///   private unnamed field of type `usize`.
270/// - Default implementations (i.e. derived implementations) for the following
271///   traits:
272///   - `Copy`, `Clone`,
273///   - `Default`,
274///   - `Ord`, `PartialOrd`, `Eq`, and `PartialEq`.
275/// - Implementations for the following traits:
276///   - `From<usize>`, `Into<usize>` (by implementing `From<$name> for usize`),
277///   - `Add<usize>`, `AddAssign<usize>`, `Sub<usize>`, `SubAssign<usize>`, and
278///   - `Sub<$name>`.
279/// - Two `const` methods to convert between the address type and `usize`:
280///   - `from_usize`, which converts an `usize` to the address type, and
281///   - `as_usize`, which converts the address type to an `usize`.
282///
283/// # Example
284///
285/// ```
286/// use ax_memory_addr::{MemoryAddr, def_usize_addr};
287///
288/// def_usize_addr! {
289///     /// A example address type.
290///     #[derive(Debug)]
291///     pub type ExampleAddr;
292/// }
293///
294/// # fn main() {
295/// const EXAMPLE: ExampleAddr = ExampleAddr::from_usize(0x1234);
296/// const EXAMPLE_USIZE: usize = EXAMPLE.as_usize();
297/// assert_eq!(EXAMPLE_USIZE, 0x1234);
298/// assert_eq!(
299///     EXAMPLE.align_down(0x10usize),
300///     ExampleAddr::from_usize(0x1230)
301/// );
302/// assert_eq!(EXAMPLE.align_up_4k(), ExampleAddr::from_usize(0x2000));
303/// # }
304/// ```
305#[macro_export]
306macro_rules! def_usize_addr {
307    (
308        $(#[$meta:meta])*
309        $vis:vis type $name:ident;
310
311        $($tt:tt)*
312    ) => {
313        #[repr(transparent)]
314        #[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
315        $(#[$meta])*
316        pub struct $name(usize);
317
318        impl $name {
319            #[doc = concat!("Converts an `usize` to an [`", stringify!($name), "`].")]
320            #[inline]
321            pub const fn from_usize(addr: usize) -> Self {
322                Self(addr)
323            }
324
325            #[doc = concat!("Converts an [`", stringify!($name), "`] to an `usize`.")]
326            #[inline]
327            pub const fn as_usize(self) -> usize {
328                self.0
329            }
330        }
331
332        impl From<usize> for $name {
333            #[inline]
334            fn from(addr: usize) -> Self {
335                Self(addr)
336            }
337        }
338
339        impl From<$name> for usize {
340            #[inline]
341            fn from(addr: $name) -> usize {
342                addr.0
343            }
344        }
345
346        impl core::ops::Add<usize> for $name {
347            type Output = Self;
348            #[inline]
349            fn add(self, rhs: usize) -> Self {
350                Self(self.0 + rhs)
351            }
352        }
353
354        impl core::ops::AddAssign<usize> for $name {
355            #[inline]
356            fn add_assign(&mut self, rhs: usize) {
357                self.0 += rhs;
358            }
359        }
360
361        impl core::ops::Sub<usize> for $name {
362            type Output = Self;
363            #[inline]
364            fn sub(self, rhs: usize) -> Self {
365                Self(self.0 - rhs)
366            }
367        }
368
369        impl core::ops::SubAssign<usize> for $name {
370            #[inline]
371            fn sub_assign(&mut self, rhs: usize) {
372                self.0 -= rhs;
373            }
374        }
375
376        impl core::ops::Sub<$name> for $name {
377            type Output = usize;
378            #[inline]
379            fn sub(self, rhs: $name) -> usize {
380                self.0 - rhs.0
381            }
382        }
383
384        $crate::def_usize_addr!($($tt)*);
385    };
386    () => {};
387}
388
389/// Creates implementations for the [`Debug`](core::fmt::Debug),
390/// [`LowerHex`](core::fmt::LowerHex), and [`UpperHex`](core::fmt::UpperHex)
391/// traits for the given address types defined by the [`def_usize_addr`].
392///
393/// For each `$name = $format;`, this macro generates the following items:
394/// - An implementation of [`core::fmt::Debug`] for the address type `$name`,
395///   which formats the address with `format_args!($format,
396///   format_args!("{:#x}", self.0))`,
397/// - An implementation of [`core::fmt::LowerHex`] for the address type `$name`,
398///   which formats the address in the same way as [`core::fmt::Debug`],
399/// - An implementation of [`core::fmt::UpperHex`] for the address type `$name`,
400///   which formats the address with `format_args!($format,
401///   format_args!("{:#X}", self.0))`.
402///
403/// # Example
404///
405/// ```
406/// use ax_memory_addr::{PhysAddr, VirtAddr, def_usize_addr, def_usize_addr_formatter};
407///
408/// def_usize_addr! {
409///     /// An example address type.
410///     pub type ExampleAddr;
411/// }
412///
413/// def_usize_addr_formatter! {
414///     ExampleAddr = "EA:{}";
415/// }
416///
417/// # fn main() {
418/// assert_eq!(format!("{:?}", PhysAddr::from(0x1abc)), "PA:0x1abc");
419/// assert_eq!(format!("{:x}", VirtAddr::from(0x1abc)), "VA:0x1abc");
420/// assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
421/// # }
422/// ```
423#[macro_export]
424macro_rules! def_usize_addr_formatter {
425    (
426        $name:ident = $format:literal;
427
428        $($tt:tt)*
429    ) => {
430        impl core::fmt::Debug for $name {
431            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
432                f.write_fmt(format_args!($format, format_args!("{:#x}", self.0)))
433            }
434        }
435
436        impl core::fmt::LowerHex for $name {
437            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
438                f.write_fmt(format_args!($format, format_args!("{:#x}", self.0)))
439            }
440        }
441
442        impl core::fmt::UpperHex for $name {
443            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
444                f.write_fmt(format_args!($format, format_args!("{:#X}", self.0)))
445            }
446        }
447
448        $crate::def_usize_addr_formatter!($($tt)*);
449    };
450    () => {};
451}
452
453def_usize_addr! {
454    /// A physical memory address.
455    pub type PhysAddr;
456
457    /// A virtual memory address.
458    pub type VirtAddr;
459}
460
461def_usize_addr_formatter! {
462    PhysAddr = "PA:{}";
463    VirtAddr = "VA:{}";
464}
465
466impl VirtAddr {
467    /// Creates a new virtual address from a raw pointer.
468    #[inline]
469    pub fn from_ptr_of<T>(ptr: *const T) -> Self {
470        Self(ptr as usize)
471    }
472
473    /// Creates a new virtual address from a mutable raw pointer.
474    #[inline]
475    pub fn from_mut_ptr_of<T>(ptr: *mut T) -> Self {
476        Self(ptr as usize)
477    }
478
479    /// Converts the virtual address to a raw pointer.
480    #[inline]
481    pub const fn as_ptr(self) -> *const u8 {
482        self.0 as *const u8
483    }
484
485    /// Converts the virtual address to a raw pointer of a specific type.
486    #[inline]
487    pub const fn as_ptr_of<T>(self) -> *const T {
488        self.0 as *const T
489    }
490
491    /// Converts the virtual address to a mutable raw pointer.
492    #[inline]
493    pub const fn as_mut_ptr(self) -> *mut u8 {
494        self.0 as *mut u8
495    }
496
497    /// Converts the virtual address to a mutable raw pointer of a specific
498    /// type.
499    #[inline]
500    pub const fn as_mut_ptr_of<T>(self) -> *mut T {
501        self.0 as *mut T
502    }
503}
504
505/// Alias for [`PhysAddr::from_usize`].
506#[macro_export]
507macro_rules! pa {
508    ($addr:expr) => {
509        $crate::PhysAddr::from_usize($addr)
510    };
511}
512
513/// Alias for [`VirtAddr::from_usize`].
514#[macro_export]
515macro_rules! va {
516    ($addr:expr) => {
517        $crate::VirtAddr::from_usize($addr)
518    };
519}
520
521#[cfg(test)]
522mod test {
523    use core::mem::size_of;
524
525    use super::*;
526
527    def_usize_addr! {
528        /// An example address type.
529        pub type ExampleAddr;
530        /// Another example address type.
531        pub type AnotherAddr;
532    }
533
534    def_usize_addr_formatter! {
535        ExampleAddr = "EA:{}";
536        AnotherAddr = "AA:{}";
537    }
538
539    #[test]
540    fn test_addr() {
541        let addr = va!(0x2000);
542        assert!(addr.is_aligned_4k());
543        assert!(!addr.is_aligned(0x10000usize));
544        assert_eq!(addr.align_offset_4k(), 0);
545        assert_eq!(addr.align_down_4k(), va!(0x2000));
546        assert_eq!(addr.align_up_4k(), va!(0x2000));
547
548        let addr = va!(0x2fff);
549        assert!(!addr.is_aligned_4k());
550        assert_eq!(addr.align_offset_4k(), 0xfff);
551        assert_eq!(addr.align_down_4k(), va!(0x2000));
552        assert_eq!(addr.align_up_4k(), va!(0x3000));
553
554        let align = 0x100000;
555        let addr = va!(align * 5) + 0x2000;
556        assert!(addr.is_aligned_4k());
557        assert!(!addr.is_aligned(align));
558        assert_eq!(addr.align_offset(align), 0x2000);
559        assert_eq!(addr.align_down(align), va!(align * 5));
560        assert_eq!(addr.align_up(align), va!(align * 6));
561    }
562
563    #[test]
564    pub fn test_addr_convert_and_comparison() {
565        let example1 = ExampleAddr::from_usize(0x1234);
566        let example2 = ExampleAddr::from(0x5678);
567        let another1 = AnotherAddr::from_usize(0x9abc);
568        let another2 = AnotherAddr::from(0xdef0);
569
570        assert_eq!(example1.as_usize(), 0x1234);
571        assert_eq!(Into::<usize>::into(example2), 0x5678);
572        assert_eq!(Into::<usize>::into(another1), 0x9abc);
573        assert_eq!(another2.as_usize(), 0xdef0);
574
575        assert_eq!(example1, ExampleAddr::from(0x1234));
576        assert_eq!(example2, ExampleAddr::from_usize(0x5678));
577        assert_eq!(another1, AnotherAddr::from_usize(0x9abc));
578        assert_eq!(another2, AnotherAddr::from(0xdef0));
579
580        assert!(example1 < example2);
581        assert!(example1 <= example2);
582        assert!(example2 > example1);
583        assert!(example2 >= example1);
584        assert!(example1 != example2);
585    }
586
587    #[test]
588    pub fn test_addr_fmt() {
589        assert_eq!(format!("{:?}", ExampleAddr::from(0x1abc)), "EA:0x1abc");
590        assert_eq!(format!("{:x}", AnotherAddr::from(0x1abc)), "AA:0x1abc");
591        assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
592    }
593
594    #[test]
595    pub fn test_alignment() {
596        let alignment = 0x1000usize;
597        let base = alignment * 2;
598        let offset = 0x123usize;
599        let addr = ExampleAddr::from_usize(base + offset);
600
601        assert_eq!(addr.align_down(alignment), ExampleAddr::from_usize(base));
602        assert_eq!(
603            addr.align_up(alignment),
604            ExampleAddr::from_usize(base + alignment)
605        );
606        assert_eq!(addr.align_offset(alignment), offset);
607        assert!(!addr.is_aligned(alignment));
608        assert!(ExampleAddr::from_usize(base).is_aligned(alignment));
609        assert_eq!(
610            ExampleAddr::from_usize(base).align_up(alignment),
611            ExampleAddr::from_usize(base)
612        );
613    }
614
615    #[test]
616    pub fn test_addr_arithmetic() {
617        let base = 0x1234usize;
618        let offset = 0x100usize;
619        let with_offset = base + offset;
620
621        let addr = ExampleAddr::from_usize(base);
622        let offset_addr = ExampleAddr::from_usize(with_offset);
623
624        assert_eq!(addr.offset(offset as isize), offset_addr);
625        assert_eq!(addr.wrapping_offset(offset as isize), offset_addr);
626        assert_eq!(offset_addr.offset_from(addr), offset as isize);
627        assert_eq!(addr.add(offset), offset_addr);
628        assert_eq!(addr.wrapping_add(offset), offset_addr);
629        assert_eq!(offset_addr.sub(offset), addr);
630        assert_eq!(offset_addr.wrapping_sub(offset), addr);
631        assert_eq!(offset_addr.sub_addr(addr), offset);
632        assert_eq!(offset_addr.wrapping_sub_addr(addr), offset);
633
634        assert_eq!(addr + offset, offset_addr);
635        assert_eq!(offset_addr - offset, addr);
636        assert_eq!(offset_addr - addr, offset);
637    }
638
639    #[test]
640    pub fn test_addr_wrapping_arithmetic() {
641        let base = usize::MAX - 0x100usize;
642        let offset = 0x200usize;
643        let with_offset = base.wrapping_add(offset);
644
645        let addr = ExampleAddr::from_usize(base);
646        let offset_addr = ExampleAddr::from_usize(with_offset);
647
648        assert_eq!(addr.wrapping_offset(offset as isize), offset_addr);
649        assert_eq!(offset_addr.wrapping_offset(-(offset as isize)), addr);
650        assert_eq!(addr.wrapping_add(offset), offset_addr);
651        assert_eq!(offset_addr.wrapping_sub(offset), addr);
652        assert_eq!(offset_addr.wrapping_sub_addr(addr), offset);
653    }
654
655    #[test]
656    pub fn test_addr_checked_arithmetic() {
657        let low_addr = ExampleAddr::from_usize(0x100usize);
658        let high_addr = ExampleAddr::from_usize(usize::MAX - 0x100usize);
659        let small_offset = 0x50usize;
660        let large_offset = 0x200usize;
661
662        assert_eq!(
663            low_addr.checked_sub(small_offset),
664            Some(low_addr.wrapping_sub(small_offset))
665        );
666        assert_eq!(low_addr.checked_sub(large_offset), None);
667        assert_eq!(
668            high_addr.checked_add(small_offset),
669            Some(high_addr.wrapping_add(small_offset))
670        );
671        assert_eq!(high_addr.checked_add(large_offset), None);
672
673        assert_eq!(
674            high_addr.checked_sub_addr(low_addr),
675            Some(usize::MAX - 0x200usize)
676        );
677        assert_eq!(low_addr.checked_sub_addr(high_addr), None);
678    }
679
680    #[test]
681    pub fn test_addr_overflowing_arithmetic() {
682        let low_addr = ExampleAddr::from_usize(0x100usize);
683        let high_addr = ExampleAddr::from_usize(usize::MAX - 0x100usize);
684        let small_offset = 0x50usize;
685        let large_offset = 0x200usize;
686
687        assert_eq!(
688            low_addr.overflowing_sub(small_offset),
689            (low_addr.wrapping_sub(small_offset), false)
690        );
691        assert_eq!(
692            low_addr.overflowing_sub(large_offset),
693            (low_addr.wrapping_sub(large_offset), true)
694        );
695        assert_eq!(
696            high_addr.overflowing_add(small_offset),
697            (high_addr.wrapping_add(small_offset), false)
698        );
699        assert_eq!(
700            high_addr.overflowing_add(large_offset),
701            (high_addr.wrapping_add(large_offset), true)
702        );
703        assert_eq!(
704            high_addr.overflowing_sub_addr(low_addr),
705            (high_addr.wrapping_sub_addr(low_addr), false)
706        );
707        assert_eq!(
708            low_addr.overflowing_sub_addr(high_addr),
709            (low_addr.wrapping_sub_addr(high_addr), true)
710        );
711    }
712
713    #[test]
714    #[should_panic]
715    pub fn test_addr_offset_overflow() {
716        let addr = ExampleAddr::from_usize(usize::MAX);
717        let _ = addr.offset(1);
718    }
719
720    #[test]
721    #[should_panic]
722    pub fn test_addr_offset_from_overflow() {
723        let addr = ExampleAddr::from_usize(usize::MAX);
724        let _ = addr.offset_from(ExampleAddr::from_usize(0));
725    }
726
727    #[test]
728    #[should_panic]
729    pub fn test_addr_offset_from_underflow() {
730        let addr = ExampleAddr::from_usize(0);
731        let _ = addr.offset_from(ExampleAddr::from_usize(usize::MAX));
732    }
733
734    #[test]
735    #[should_panic]
736    pub fn test_addr_add_overflow() {
737        let addr = ExampleAddr::from_usize(usize::MAX);
738        let _ = addr.add(1);
739    }
740
741    #[test]
742    #[should_panic]
743    pub fn test_addr_sub_underflow() {
744        let addr = ExampleAddr::from_usize(0);
745        let _ = addr.sub(1);
746    }
747
748    #[test]
749    #[should_panic]
750    pub fn test_addr_sub_addr_overflow() {
751        let addr = ExampleAddr::from_usize(0);
752        let _ = addr.sub_addr(ExampleAddr::from_usize(1));
753    }
754
755    #[test]
756    pub fn test_virt_addr_ptr() {
757        let a: [usize; 4] = [0x1234, 0x5678, 0x9abc, 0xdef0];
758
759        let va0 = VirtAddr::from_ptr_of(&a as *const usize);
760        let va1 = va0.add(size_of::<usize>());
761        let va2 = va1.add(size_of::<usize>());
762        let va3 = va2.add(size_of::<usize>());
763
764        let p0 = va0.as_ptr() as *const usize;
765        let p1 = va1.as_ptr_of::<usize>();
766        let p2 = va2.as_mut_ptr() as *mut usize;
767        let p3 = va3.as_mut_ptr_of::<usize>();
768
769        // testing conversion back to virt addr
770        assert_eq!(va0, VirtAddr::from_ptr_of(p0));
771        assert_eq!(va1, VirtAddr::from_ptr_of(p1));
772        assert_eq!(va2, VirtAddr::from_mut_ptr_of(p2));
773        assert_eq!(va3, VirtAddr::from_mut_ptr_of(p3));
774
775        // testing pointer read/write
776        assert!(unsafe { *p0 } == a[0]);
777        assert!(unsafe { *p1 } == a[1]);
778        assert!(unsafe { *p2 } == a[2]);
779        assert!(unsafe { *p3 } == a[3]);
780
781        unsafe {
782            *p2 = 0xdeadbeef;
783        }
784        unsafe {
785            *p3 = 0xcafebabe;
786        }
787        assert_eq!(a[2], 0xdeadbeef);
788        assert_eq!(a[3], 0xcafebabe);
789    }
790}