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 memory_addr::{def_usize_addr, MemoryAddr};
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!(EXAMPLE.align_down(0x10usize), ExampleAddr::from_usize(0x1230));
299/// assert_eq!(EXAMPLE.align_up_4k(), ExampleAddr::from_usize(0x2000));
300/// # }
301/// ```
302#[macro_export]
303macro_rules! def_usize_addr {
304    (
305        $(#[$meta:meta])*
306        $vis:vis type $name:ident;
307
308        $($tt:tt)*
309    ) => {
310        #[repr(transparent)]
311        #[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
312        $(#[$meta])*
313        pub struct $name(usize);
314
315        impl $name {
316            #[doc = concat!("Converts an `usize` to an [`", stringify!($name), "`].")]
317            #[inline]
318            pub const fn from_usize(addr: usize) -> Self {
319                Self(addr)
320            }
321
322            #[doc = concat!("Converts an [`", stringify!($name), "`] to an `usize`.")]
323            #[inline]
324            pub const fn as_usize(self) -> usize {
325                self.0
326            }
327        }
328
329        impl From<usize> for $name {
330            #[inline]
331            fn from(addr: usize) -> Self {
332                Self(addr)
333            }
334        }
335
336        impl From<$name> for usize {
337            #[inline]
338            fn from(addr: $name) -> usize {
339                addr.0
340            }
341        }
342
343        impl core::ops::Add<usize> for $name {
344            type Output = Self;
345            #[inline]
346            fn add(self, rhs: usize) -> Self {
347                Self(self.0 + rhs)
348            }
349        }
350
351        impl core::ops::AddAssign<usize> for $name {
352            #[inline]
353            fn add_assign(&mut self, rhs: usize) {
354                self.0 += rhs;
355            }
356        }
357
358        impl core::ops::Sub<usize> for $name {
359            type Output = Self;
360            #[inline]
361            fn sub(self, rhs: usize) -> Self {
362                Self(self.0 - rhs)
363            }
364        }
365
366        impl core::ops::SubAssign<usize> for $name {
367            #[inline]
368            fn sub_assign(&mut self, rhs: usize) {
369                self.0 -= rhs;
370            }
371        }
372
373        impl core::ops::Sub<$name> for $name {
374            type Output = usize;
375            #[inline]
376            fn sub(self, rhs: $name) -> usize {
377                self.0 - rhs.0
378            }
379        }
380
381        $crate::def_usize_addr!($($tt)*);
382    };
383    () => {};
384}
385
386/// Creates implementations for the [`Debug`](core::fmt::Debug),
387/// [`LowerHex`](core::fmt::LowerHex), and [`UpperHex`](core::fmt::UpperHex)
388/// traits for the given address types defined by the [`def_usize_addr`].
389///
390/// For each `$name = $format;`, this macro generates the following items:
391/// - An implementation of [`core::fmt::Debug`] for the address type `$name`,
392///   which formats the address with `format_args!($format,
393///   format_args!("{:#x}", self.0))`,
394/// - An implementation of [`core::fmt::LowerHex`] for the address type `$name`,
395///   which formats the address in the same way as [`core::fmt::Debug`],
396/// - An implementation of [`core::fmt::UpperHex`] for the address type `$name`,
397///   which formats the address with `format_args!($format,
398///   format_args!("{:#X}", self.0))`.
399///
400/// # Example
401///
402/// ```
403/// use memory_addr::{PhysAddr, VirtAddr, def_usize_addr, def_usize_addr_formatter};
404///
405/// def_usize_addr! {
406///     /// An example address type.
407///     pub type ExampleAddr;
408/// }
409///
410/// def_usize_addr_formatter! {
411///     ExampleAddr = "EA:{}";
412/// }
413///
414/// # fn main() {
415/// assert_eq!(format!("{:?}", PhysAddr::from(0x1abc)), "PA:0x1abc");
416/// assert_eq!(format!("{:x}", VirtAddr::from(0x1abc)), "VA:0x1abc");
417/// assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
418/// # }
419/// ```
420#[macro_export]
421macro_rules! def_usize_addr_formatter {
422    (
423        $name:ident = $format:literal;
424
425        $($tt:tt)*
426    ) => {
427        impl core::fmt::Debug for $name {
428            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
429                f.write_fmt(format_args!($format, format_args!("{:#x}", self.0)))
430            }
431        }
432
433        impl core::fmt::LowerHex for $name {
434            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
435                f.write_fmt(format_args!($format, format_args!("{:#x}", self.0)))
436            }
437        }
438
439        impl core::fmt::UpperHex for $name {
440            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
441                f.write_fmt(format_args!($format, format_args!("{:#X}", self.0)))
442            }
443        }
444
445        $crate::def_usize_addr_formatter!($($tt)*);
446    };
447    () => {};
448}
449
450def_usize_addr! {
451    /// A physical memory address.
452    pub type PhysAddr;
453
454    /// A virtual memory address.
455    pub type VirtAddr;
456}
457
458def_usize_addr_formatter! {
459    PhysAddr = "PA:{}";
460    VirtAddr = "VA:{}";
461}
462
463impl VirtAddr {
464    /// Creates a new virtual address from a raw pointer.
465    #[inline]
466    pub fn from_ptr_of<T>(ptr: *const T) -> Self {
467        Self(ptr as usize)
468    }
469
470    /// Creates a new virtual address from a mutable raw pointer.
471    #[inline]
472    pub fn from_mut_ptr_of<T>(ptr: *mut T) -> Self {
473        Self(ptr as usize)
474    }
475
476    /// Converts the virtual address to a raw pointer.
477    #[inline]
478    pub const fn as_ptr(self) -> *const u8 {
479        self.0 as *const u8
480    }
481
482    /// Converts the virtual address to a raw pointer of a specific type.
483    #[inline]
484    pub const fn as_ptr_of<T>(self) -> *const T {
485        self.0 as *const T
486    }
487
488    /// Converts the virtual address to a mutable raw pointer.
489    #[inline]
490    pub const fn as_mut_ptr(self) -> *mut u8 {
491        self.0 as *mut u8
492    }
493
494    /// Converts the virtual address to a mutable raw pointer of a specific
495    /// type.
496    #[inline]
497    pub const fn as_mut_ptr_of<T>(self) -> *mut T {
498        self.0 as *mut T
499    }
500}
501
502/// Alias for [`PhysAddr::from_usize`].
503#[macro_export]
504macro_rules! pa {
505    ($addr:expr) => {
506        $crate::PhysAddr::from_usize($addr)
507    };
508}
509
510/// Alias for [`VirtAddr::from_usize`].
511#[macro_export]
512macro_rules! va {
513    ($addr:expr) => {
514        $crate::VirtAddr::from_usize($addr)
515    };
516}
517
518#[cfg(test)]
519mod test {
520    use core::mem::size_of;
521
522    use super::*;
523
524    def_usize_addr! {
525        /// An example address type.
526        pub type ExampleAddr;
527        /// Another example address type.
528        pub type AnotherAddr;
529    }
530
531    def_usize_addr_formatter! {
532        ExampleAddr = "EA:{}";
533        AnotherAddr = "AA:{}";
534    }
535
536    #[test]
537    fn test_addr() {
538        let addr = va!(0x2000);
539        assert!(addr.is_aligned_4k());
540        assert!(!addr.is_aligned(0x10000usize));
541        assert_eq!(addr.align_offset_4k(), 0);
542        assert_eq!(addr.align_down_4k(), va!(0x2000));
543        assert_eq!(addr.align_up_4k(), va!(0x2000));
544
545        let addr = va!(0x2fff);
546        assert!(!addr.is_aligned_4k());
547        assert_eq!(addr.align_offset_4k(), 0xfff);
548        assert_eq!(addr.align_down_4k(), va!(0x2000));
549        assert_eq!(addr.align_up_4k(), va!(0x3000));
550
551        let align = 0x100000;
552        let addr = va!(align * 5) + 0x2000;
553        assert!(addr.is_aligned_4k());
554        assert!(!addr.is_aligned(align));
555        assert_eq!(addr.align_offset(align), 0x2000);
556        assert_eq!(addr.align_down(align), va!(align * 5));
557        assert_eq!(addr.align_up(align), va!(align * 6));
558    }
559
560    #[test]
561    pub fn test_addr_convert_and_comparison() {
562        let example1 = ExampleAddr::from_usize(0x1234);
563        let example2 = ExampleAddr::from(0x5678);
564        let another1 = AnotherAddr::from_usize(0x9abc);
565        let another2 = AnotherAddr::from(0xdef0);
566
567        assert_eq!(example1.as_usize(), 0x1234);
568        assert_eq!(Into::<usize>::into(example2), 0x5678);
569        assert_eq!(Into::<usize>::into(another1), 0x9abc);
570        assert_eq!(another2.as_usize(), 0xdef0);
571
572        assert_eq!(example1, ExampleAddr::from(0x1234));
573        assert_eq!(example2, ExampleAddr::from_usize(0x5678));
574        assert_eq!(another1, AnotherAddr::from_usize(0x9abc));
575        assert_eq!(another2, AnotherAddr::from(0xdef0));
576
577        assert!(example1 < example2);
578        assert!(example1 <= example2);
579        assert!(example2 > example1);
580        assert!(example2 >= example1);
581        assert!(example1 != example2);
582    }
583
584    #[test]
585    pub fn test_addr_fmt() {
586        assert_eq!(format!("{:?}", ExampleAddr::from(0x1abc)), "EA:0x1abc");
587        assert_eq!(format!("{:x}", AnotherAddr::from(0x1abc)), "AA:0x1abc");
588        assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
589    }
590
591    #[test]
592    pub fn test_alignment() {
593        let alignment = 0x1000usize;
594        let base = alignment * 2;
595        let offset = 0x123usize;
596        let addr = ExampleAddr::from_usize(base + offset);
597
598        assert_eq!(addr.align_down(alignment), ExampleAddr::from_usize(base));
599        assert_eq!(
600            addr.align_up(alignment),
601            ExampleAddr::from_usize(base + alignment)
602        );
603        assert_eq!(addr.align_offset(alignment), offset);
604        assert!(!addr.is_aligned(alignment));
605        assert!(ExampleAddr::from_usize(base).is_aligned(alignment));
606        assert_eq!(
607            ExampleAddr::from_usize(base).align_up(alignment),
608            ExampleAddr::from_usize(base)
609        );
610    }
611
612    #[test]
613    pub fn test_addr_arithmetic() {
614        let base = 0x1234usize;
615        let offset = 0x100usize;
616        let with_offset = base + offset;
617
618        let addr = ExampleAddr::from_usize(base);
619        let offset_addr = ExampleAddr::from_usize(with_offset);
620
621        assert_eq!(addr.offset(offset as isize), offset_addr);
622        assert_eq!(addr.wrapping_offset(offset as isize), offset_addr);
623        assert_eq!(offset_addr.offset_from(addr), offset as isize);
624        assert_eq!(addr.add(offset), offset_addr);
625        assert_eq!(addr.wrapping_add(offset), offset_addr);
626        assert_eq!(offset_addr.sub(offset), addr);
627        assert_eq!(offset_addr.wrapping_sub(offset), addr);
628        assert_eq!(offset_addr.sub_addr(addr), offset);
629        assert_eq!(offset_addr.wrapping_sub_addr(addr), offset);
630
631        assert_eq!(addr + offset, offset_addr);
632        assert_eq!(offset_addr - offset, addr);
633        assert_eq!(offset_addr - addr, offset);
634    }
635
636    #[test]
637    pub fn test_addr_wrapping_arithmetic() {
638        let base = usize::MAX - 0x100usize;
639        let offset = 0x200usize;
640        let with_offset = base.wrapping_add(offset);
641
642        let addr = ExampleAddr::from_usize(base);
643        let offset_addr = ExampleAddr::from_usize(with_offset);
644
645        assert_eq!(addr.wrapping_offset(offset as isize), offset_addr);
646        assert_eq!(offset_addr.wrapping_offset(-(offset as isize)), addr);
647        assert_eq!(addr.wrapping_add(offset), offset_addr);
648        assert_eq!(offset_addr.wrapping_sub(offset), addr);
649        assert_eq!(offset_addr.wrapping_sub_addr(addr), offset);
650    }
651
652    #[test]
653    pub fn test_addr_checked_arithmetic() {
654        let low_addr = ExampleAddr::from_usize(0x100usize);
655        let high_addr = ExampleAddr::from_usize(usize::MAX - 0x100usize);
656        let small_offset = 0x50usize;
657        let large_offset = 0x200usize;
658
659        assert_eq!(
660            low_addr.checked_sub(small_offset),
661            Some(low_addr.wrapping_sub(small_offset))
662        );
663        assert_eq!(low_addr.checked_sub(large_offset), None);
664        assert_eq!(
665            high_addr.checked_add(small_offset),
666            Some(high_addr.wrapping_add(small_offset))
667        );
668        assert_eq!(high_addr.checked_add(large_offset), None);
669
670        assert_eq!(
671            high_addr.checked_sub_addr(low_addr),
672            Some(usize::MAX - 0x200usize)
673        );
674        assert_eq!(low_addr.checked_sub_addr(high_addr), None);
675    }
676
677    #[test]
678    pub fn test_addr_overflowing_arithmetic() {
679        let low_addr = ExampleAddr::from_usize(0x100usize);
680        let high_addr = ExampleAddr::from_usize(usize::MAX - 0x100usize);
681        let small_offset = 0x50usize;
682        let large_offset = 0x200usize;
683
684        assert_eq!(
685            low_addr.overflowing_sub(small_offset),
686            (low_addr.wrapping_sub(small_offset), false)
687        );
688        assert_eq!(
689            low_addr.overflowing_sub(large_offset),
690            (low_addr.wrapping_sub(large_offset), true)
691        );
692        assert_eq!(
693            high_addr.overflowing_add(small_offset),
694            (high_addr.wrapping_add(small_offset), false)
695        );
696        assert_eq!(
697            high_addr.overflowing_add(large_offset),
698            (high_addr.wrapping_add(large_offset), true)
699        );
700        assert_eq!(
701            high_addr.overflowing_sub_addr(low_addr),
702            (high_addr.wrapping_sub_addr(low_addr), false)
703        );
704        assert_eq!(
705            low_addr.overflowing_sub_addr(high_addr),
706            (low_addr.wrapping_sub_addr(high_addr), true)
707        );
708    }
709
710    #[test]
711    #[should_panic]
712    pub fn test_addr_offset_overflow() {
713        let addr = ExampleAddr::from_usize(usize::MAX);
714        let _ = addr.offset(1);
715    }
716
717    #[test]
718    #[should_panic]
719    pub fn test_addr_offset_from_overflow() {
720        let addr = ExampleAddr::from_usize(usize::MAX);
721        let _ = addr.offset_from(ExampleAddr::from_usize(0));
722    }
723
724    #[test]
725    #[should_panic]
726    pub fn test_addr_offset_from_underflow() {
727        let addr = ExampleAddr::from_usize(0);
728        let _ = addr.offset_from(ExampleAddr::from_usize(usize::MAX));
729    }
730
731    #[test]
732    #[should_panic]
733    pub fn test_addr_add_overflow() {
734        let addr = ExampleAddr::from_usize(usize::MAX);
735        let _ = addr.add(1);
736    }
737
738    #[test]
739    #[should_panic]
740    pub fn test_addr_sub_underflow() {
741        let addr = ExampleAddr::from_usize(0);
742        let _ = addr.sub(1);
743    }
744
745    #[test]
746    #[should_panic]
747    pub fn test_addr_sub_addr_overflow() {
748        let addr = ExampleAddr::from_usize(0);
749        let _ = addr.sub_addr(ExampleAddr::from_usize(1));
750    }
751
752    #[test]
753    pub fn test_virt_addr_ptr() {
754        let a: [usize; 4] = [0x1234, 0x5678, 0x9abc, 0xdef0];
755
756        let va0 = VirtAddr::from_ptr_of(&a as *const usize);
757        let va1 = va0.add(size_of::<usize>());
758        let va2 = va1.add(size_of::<usize>());
759        let va3 = va2.add(size_of::<usize>());
760
761        let p0 = va0.as_ptr() as *const usize;
762        let p1 = va1.as_ptr_of::<usize>();
763        let p2 = va2.as_mut_ptr() as *mut usize;
764        let p3 = va3.as_mut_ptr_of::<usize>();
765
766        // testing conversion back to virt addr
767        assert_eq!(va0, VirtAddr::from_ptr_of(p0));
768        assert_eq!(va1, VirtAddr::from_ptr_of(p1));
769        assert_eq!(va2, VirtAddr::from_mut_ptr_of(p2));
770        assert_eq!(va3, VirtAddr::from_mut_ptr_of(p3));
771
772        // testing pointer read/write
773        assert!(unsafe { *p0 } == a[0]);
774        assert!(unsafe { *p1 } == a[1]);
775        assert!(unsafe { *p2 } == a[2]);
776        assert!(unsafe { *p3 } == a[3]);
777
778        unsafe {
779            *p2 = 0xdeadbeef;
780        }
781        unsafe {
782            *p3 = 0xcafebabe;
783        }
784        assert_eq!(a[2], 0xdeadbeef);
785        assert_eq!(a[3], 0xcafebabe);
786    }
787}