1#![no_std]
8#![deny(clippy::undocumented_unsafe_blocks)]
9#![deny(unsafe_op_in_unsafe_fn)]
10
11#[cfg(target_arch = "aarch64")]
12mod aarch64_mmio;
13pub mod fields;
14mod physical;
15#[cfg(not(target_arch = "aarch64"))]
16mod volatile_mmio;
17
18use crate::fields::{ReadOnly, ReadPure, ReadPureWrite, ReadWrite, WriteOnly};
19use core::{array, fmt::Debug, marker::PhantomData, ops::Deref, ptr, ptr::NonNull};
20pub use physical::PhysicalInstance;
21use zerocopy::{FromBytes, Immutable, IntoBytes};
22
23pub struct UniqueMmioPointer<'a, T: ?Sized>(SharedMmioPointer<'a, T>);
31
32impl<T: ?Sized> Debug for UniqueMmioPointer<'_, T> {
36 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37 f.debug_tuple("UniqueMmioPointer")
38 .field(&self.0.regs)
39 .finish()
40 }
41}
42
43impl<T: ?Sized> PartialEq for UniqueMmioPointer<'_, T> {
44 fn eq(&self, other: &Self) -> bool {
45 self.0 == other.0
46 }
47}
48
49impl<T: ?Sized> Eq for UniqueMmioPointer<'_, T> {}
50
51impl<T: ?Sized> UniqueMmioPointer<'_, T> {
52 pub const unsafe fn new(regs: NonNull<T>) -> Self {
64 Self(SharedMmioPointer {
65 regs,
66 phantom: PhantomData,
67 })
68 }
69
70 pub const unsafe fn child<U: ?Sized>(&mut self, regs: NonNull<U>) -> UniqueMmioPointer<'_, U> {
79 UniqueMmioPointer(SharedMmioPointer {
80 regs,
81 phantom: PhantomData,
82 })
83 }
84
85 pub const fn ptr_mut(&mut self) -> *mut T {
87 self.0.regs.as_ptr()
88 }
89
90 pub const fn ptr_nonnull(&mut self) -> NonNull<T> {
92 self.0.regs
93 }
94
95 pub const fn reborrow(&mut self) -> UniqueMmioPointer<'_, T> {
97 let ptr = self.ptr_nonnull();
98 unsafe { self.child(ptr) }
101 }
102}
103
104impl<'a, T: ?Sized> UniqueMmioPointer<'a, T> {
105 pub const unsafe fn split_child<U: ?Sized>(
117 &mut self,
118 regs: NonNull<U>,
119 ) -> UniqueMmioPointer<'a, U> {
120 UniqueMmioPointer(SharedMmioPointer {
121 regs,
122 phantom: PhantomData,
123 })
124 }
125}
126
127impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
128 pub fn read(&mut self) -> T {
130 unsafe { self.read_unsafe().0 }
133 }
134}
135
136impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadWrite<T>> {
137 pub fn write(&mut self, value: T) {
139 unsafe {
142 self.write_unsafe(ReadWrite(value));
143 }
144 }
145}
146
147impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, ReadPureWrite<T>> {
148 pub fn write(&mut self, value: T) {
150 unsafe {
153 self.write_unsafe(ReadPureWrite(value));
154 }
155 }
156}
157
158impl<T: FromBytes + IntoBytes> UniqueMmioPointer<'_, ReadOnly<T>> {
159 pub fn read(&mut self) -> T {
161 unsafe { self.read_unsafe().0 }
164 }
165}
166
167impl<T: Immutable + IntoBytes> UniqueMmioPointer<'_, WriteOnly<T>> {
168 pub fn write(&mut self, value: T) {
170 unsafe {
173 self.write_unsafe(WriteOnly(value));
174 }
175 }
176}
177
178impl<'a, T> UniqueMmioPointer<'a, [T]> {
179 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
194 if index >= self.0.len() {
195 return None;
196 }
197 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
200 Some(unsafe { self.child(regs) })
203 }
204
205 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
225 if index >= self.0.len() {
226 return None;
227 }
228 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
231 Some(unsafe { self.split_child(regs) })
235 }
236}
237
238impl<'a, T, const LEN: usize> UniqueMmioPointer<'a, [T; LEN]> {
239 pub fn split(&mut self) -> [UniqueMmioPointer<'_, T>; LEN] {
241 array::from_fn(|i| {
242 UniqueMmioPointer(SharedMmioPointer {
243 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[i] }).unwrap(),
246 phantom: PhantomData,
247 })
248 })
249 }
250
251 pub fn split_some<const N: usize>(
256 mut self,
257 chosen: [usize; N],
258 ) -> [UniqueMmioPointer<'a, T>; N] {
259 for (i, a) in chosen.iter().enumerate() {
260 for (j, b) in chosen.iter().enumerate() {
261 assert!(i == j || a != b, "chosen array must not contain duplicates");
262 }
263 }
264 chosen.map(|chosen_index| {
265 UniqueMmioPointer(SharedMmioPointer {
266 regs: NonNull::new(unsafe { &raw mut (*self.ptr_mut())[chosen_index] }).unwrap(),
270 phantom: PhantomData,
271 })
272 })
273 }
274
275 pub const fn as_mut_slice(&mut self) -> UniqueMmioPointer<'_, [T]> {
277 let regs = NonNull::new(self.ptr_mut()).unwrap();
278 unsafe { self.child(regs) }
281 }
282
283 pub const fn get(&mut self, index: usize) -> Option<UniqueMmioPointer<'_, T>> {
299 if index >= LEN {
300 return None;
301 }
302 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
305 Some(unsafe { self.child(regs) })
308 }
309
310 pub const fn take(mut self, index: usize) -> Option<UniqueMmioPointer<'a, T>> {
330 if index >= LEN {
331 return None;
332 }
333 let regs = NonNull::new(unsafe { &raw mut (*self.ptr_mut())[index] }).unwrap();
336 Some(unsafe { self.split_child(regs) })
340 }
341}
342
343impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>> for UniqueMmioPointer<'a, [T]> {
344 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
345 let regs = NonNull::new(value.ptr_mut()).unwrap();
346 unsafe { UniqueMmioPointer::new(regs) }
349 }
350}
351
352impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T; 1]> {
353 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
354 let regs = NonNull::new(value.ptr_mut()).unwrap().cast();
355 unsafe { UniqueMmioPointer::new(regs) }
358 }
359}
360
361impl<'a, T> From<UniqueMmioPointer<'a, T>> for UniqueMmioPointer<'a, [T]> {
362 fn from(mut value: UniqueMmioPointer<'a, T>) -> Self {
363 let array: *mut [T; 1] = value.ptr_mut().cast();
364 let regs = NonNull::new(array).unwrap();
365 unsafe { UniqueMmioPointer::new(regs) }
368 }
369}
370
371impl<'a, T, const LEN: usize> From<UniqueMmioPointer<'a, [T; LEN]>>
372 for [UniqueMmioPointer<'a, T>; LEN]
373{
374 fn from(mut value: UniqueMmioPointer<'a, [T; LEN]>) -> Self {
375 array::from_fn(|i| {
376 let item_pointer = value.get(i).unwrap().ptr_mut();
377 unsafe { value.split_child(core::ptr::NonNull::new(item_pointer).unwrap()) }
380 })
381 }
382}
383
384impl<'a, T: ?Sized> From<&'a mut T> for UniqueMmioPointer<'a, T> {
385 fn from(r: &'a mut T) -> Self {
386 Self(SharedMmioPointer {
387 regs: r.into(),
388 phantom: PhantomData,
389 })
390 }
391}
392
393impl<'a, T: ?Sized> Deref for UniqueMmioPointer<'a, T> {
394 type Target = SharedMmioPointer<'a, T>;
395
396 fn deref(&self) -> &Self::Target {
397 &self.0
398 }
399}
400
401pub struct SharedMmioPointer<'a, T: ?Sized> {
405 regs: NonNull<T>,
406 phantom: PhantomData<&'a T>,
407}
408
409impl<T: ?Sized> Debug for SharedMmioPointer<'_, T> {
413 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
414 f.debug_tuple("SharedMmioPointer")
415 .field(&self.regs)
416 .finish()
417 }
418}
419
420impl<T: ?Sized> PartialEq for SharedMmioPointer<'_, T> {
421 fn eq(&self, other: &Self) -> bool {
422 ptr::eq(self.regs.as_ptr(), other.regs.as_ptr())
423 }
424}
425
426impl<T: ?Sized> Eq for SharedMmioPointer<'_, T> {}
427
428impl<T: ?Sized> Clone for SharedMmioPointer<'_, T> {
429 fn clone(&self) -> Self {
430 *self
431 }
432}
433
434impl<T: ?Sized> Copy for SharedMmioPointer<'_, T> {}
435
436impl<'a, T: ?Sized> SharedMmioPointer<'a, T> {
437 pub const unsafe fn child<U: ?Sized>(&self, regs: NonNull<U>) -> SharedMmioPointer<'a, U> {
446 SharedMmioPointer {
447 regs,
448 phantom: PhantomData,
449 }
450 }
451
452 pub const fn ptr(&self) -> *const T {
454 self.regs.as_ptr()
455 }
456}
457
458unsafe impl<T: ?Sized + Send + Sync> Send for SharedMmioPointer<'_, T> {}
462
463impl<'a, T: ?Sized> From<&'a T> for SharedMmioPointer<'a, T> {
464 fn from(r: &'a T) -> Self {
465 Self {
466 regs: r.into(),
467 phantom: PhantomData,
468 }
469 }
470}
471
472impl<'a, T: ?Sized> From<UniqueMmioPointer<'a, T>> for SharedMmioPointer<'a, T> {
473 fn from(unique: UniqueMmioPointer<'a, T>) -> Self {
474 unique.0
475 }
476}
477
478impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPure<T>> {
479 pub fn read(&self) -> T {
481 unsafe { self.read_unsafe().0 }
485 }
486}
487
488impl<T: FromBytes + IntoBytes> SharedMmioPointer<'_, ReadPureWrite<T>> {
489 pub fn read(&self) -> T {
491 unsafe { self.read_unsafe().0 }
495 }
496}
497
498impl<'a, T> SharedMmioPointer<'a, [T]> {
499 pub fn split_some<const N: usize>(self, chosen: [usize; N]) -> [UniqueMmioPointer<'a, T>; N] {
504 for (i, a) in chosen.iter().enumerate() {
505 for (j, b) in chosen.iter().enumerate() {
506 assert!(i == j || a != b, "chosen array must not contain duplicates");
507 }
508 }
509 chosen.map(|chosen_index| {
510 UniqueMmioPointer(SharedMmioPointer {
511 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[chosen_index] })
515 .unwrap(),
516 phantom: PhantomData,
517 })
518 })
519 }
520
521 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
524 if index >= self.len() {
525 return None;
526 }
527 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
529 Some(unsafe { self.child(regs) })
532 }
533
534 pub const fn len(&self) -> usize {
536 self.regs.len()
537 }
538
539 pub const fn is_empty(&self) -> bool {
541 self.regs.is_empty()
542 }
543}
544
545impl<'a, T, const LEN: usize> SharedMmioPointer<'a, [T; LEN]> {
546 pub fn split(&self) -> [SharedMmioPointer<'a, T>; LEN] {
548 array::from_fn(|i| SharedMmioPointer {
549 regs: NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[i] }).unwrap(),
552 phantom: PhantomData,
553 })
554 }
555
556 pub const fn as_slice(&self) -> SharedMmioPointer<'a, [T]> {
558 let regs = NonNull::new(self.regs.as_ptr()).unwrap();
559 unsafe { self.child(regs) }
562 }
563
564 pub const fn get(&self, index: usize) -> Option<SharedMmioPointer<'a, T>> {
567 if index >= LEN {
568 return None;
569 }
570 let regs = NonNull::new(unsafe { &raw mut (*self.regs.as_ptr())[index] }).unwrap();
572 Some(unsafe { self.child(regs) })
575 }
576}
577
578impl<'a, T, const LEN: usize> From<SharedMmioPointer<'a, [T; LEN]>> for SharedMmioPointer<'a, [T]> {
579 fn from(value: SharedMmioPointer<'a, [T; LEN]>) -> Self {
580 let regs = NonNull::new(value.regs.as_ptr()).unwrap();
581 SharedMmioPointer {
582 regs,
583 phantom: PhantomData,
584 }
585 }
586}
587
588impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T; 1]> {
589 fn from(value: SharedMmioPointer<'a, T>) -> Self {
590 let regs = NonNull::new(value.regs.as_ptr()).unwrap().cast();
591 SharedMmioPointer {
592 regs,
593 phantom: PhantomData,
594 }
595 }
596}
597
598impl<'a, T> From<SharedMmioPointer<'a, T>> for SharedMmioPointer<'a, [T]> {
599 fn from(value: SharedMmioPointer<'a, T>) -> Self {
600 let array: *mut [T; 1] = value.regs.as_ptr().cast();
601 let regs = NonNull::new(array).unwrap();
602 SharedMmioPointer {
603 regs,
604 phantom: PhantomData,
605 }
606 }
607}
608
609#[macro_export]
611macro_rules! field {
612 ($mmio_pointer:expr, $field:ident) => {{
613 let mmio_pointer: &mut $crate::UniqueMmioPointer<_> = &mut $mmio_pointer;
615 unsafe {
619 let child_pointer =
620 core::ptr::NonNull::new(&raw mut (*mmio_pointer.ptr_mut()).$field).unwrap();
621 mmio_pointer.child(child_pointer)
622 }
623 }};
624}
625
626#[macro_export]
632macro_rules! split_fields {
633 ($mmio_pointer:expr, $( $field:ident ),+) => {{
634 let mut mmio_pointer: $crate::UniqueMmioPointer<_> = $mmio_pointer;
636 let pointer = mmio_pointer.ptr_mut();
637 let ret = (
638 $(
639 {
644 let child_pointer = core::ptr::NonNull::new(&raw mut (*pointer).$field).unwrap();
645 mmio_pointer.split_child(child_pointer)
646 }
647 ),+
648 );
649 ret
650 }};
651}
652
653#[macro_export]
655macro_rules! field_shared {
656 ($mmio_pointer:expr, $field:ident) => {{
657 let mmio_pointer: &$crate::SharedMmioPointer<_> = &$mmio_pointer;
659 unsafe {
663 let child_pointer =
664 core::ptr::NonNull::new((&raw const (*mmio_pointer.ptr()).$field).cast_mut())
665 .unwrap();
666 mmio_pointer.child(child_pointer)
667 }
668 }};
669}
670
671#[cfg(test)]
672mod tests {
673 use super::*;
674
675 #[test]
676 fn fields() {
677 #[repr(C)]
678 struct Foo {
679 a: ReadWrite<u32>,
680 b: ReadOnly<u32>,
681 c: ReadPure<u32>,
682 }
683
684 let mut foo = Foo {
685 a: ReadWrite(1),
686 b: ReadOnly(2),
687 c: ReadPure(3),
688 };
689 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
690
691 let mut owned_a: UniqueMmioPointer<ReadWrite<u32>> = field!(owned, a);
692 assert_eq!(owned_a.read(), 1);
693 owned_a.write(42);
694 assert_eq!(owned_a.read(), 42);
695 field!(owned, a).write(44);
696 assert_eq!(field!(owned, a).read(), 44);
697
698 let mut owned_b: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, b);
699 assert_eq!(owned_b.read(), 2);
700
701 let owned_c: UniqueMmioPointer<ReadPure<u32>> = field!(owned, c);
702 assert_eq!(owned_c.read(), 3);
703 assert_eq!(field!(owned, c).read(), 3);
704 }
705
706 #[test]
707 fn shared_fields() {
708 #[repr(C)]
709 struct Foo {
710 a: ReadPureWrite<u32>,
711 b: ReadPure<u32>,
712 }
713
714 let foo = Foo {
715 a: ReadPureWrite(1),
716 b: ReadPure(2),
717 };
718 let shared: SharedMmioPointer<Foo> = SharedMmioPointer::from(&foo);
719
720 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(shared, a);
721 assert_eq!(shared_a.read(), 1);
722 assert_eq!(field_shared!(shared, a).read(), 1);
723
724 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(shared, b);
725 assert_eq!(shared_b.read(), 2);
726 }
727
728 #[test]
729 fn shared_from_unique() {
730 #[repr(C)]
731 struct Foo {
732 a: ReadPureWrite<u32>,
733 b: ReadPure<u32>,
734 }
735
736 let mut foo = Foo {
737 a: ReadPureWrite(1),
738 b: ReadPure(2),
739 };
740 let unique: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
741
742 let shared_a: SharedMmioPointer<ReadPureWrite<u32>> = field_shared!(unique, a);
743 assert_eq!(shared_a.read(), 1);
744
745 let shared_b: SharedMmioPointer<ReadPure<u32>> = field_shared!(unique, b);
746 assert_eq!(shared_b.read(), 2);
747 }
748
749 #[test]
750 fn restricted_fields() {
751 #[repr(C)]
752 struct Foo {
753 r: ReadOnly<u32>,
754 w: WriteOnly<u32>,
755 u: u32,
756 }
757
758 let mut foo = Foo {
759 r: ReadOnly(1),
760 w: WriteOnly(2),
761 u: 3,
762 };
763 let mut owned: UniqueMmioPointer<Foo> = UniqueMmioPointer::from(&mut foo);
764
765 let mut owned_r: UniqueMmioPointer<ReadOnly<u32>> = field!(owned, r);
766 assert_eq!(owned_r.read(), 1);
767
768 let mut owned_w: UniqueMmioPointer<WriteOnly<u32>> = field!(owned, w);
769 owned_w.write(42);
770
771 let mut owned_u: UniqueMmioPointer<u32> = field!(owned, u);
772 unsafe {
774 assert_eq!(owned_u.read_unsafe(), 3);
775 owned_u.write_unsafe(42);
776 assert_eq!(owned_u.read_unsafe(), 42);
777 }
778 }
779
780 #[test]
781 fn array() {
782 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
783 let mut owned = UniqueMmioPointer::from(&mut foo);
784
785 let mut parts = owned.split();
786 assert_eq!(parts[0].read(), 1);
787 assert_eq!(parts[1].read(), 2);
788 assert_eq!(owned.split()[2].read(), 3);
789 }
790
791 #[test]
792 fn array_shared() {
793 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
794 let shared = SharedMmioPointer::from(&foo);
795
796 let parts = shared.split();
797 assert_eq!(parts[0].read(), 1);
798 assert_eq!(parts[1].read(), 2);
799 assert_eq!(shared.split()[2].read(), 3);
800 }
801
802 #[test]
803 fn slice() {
804 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
805 let mut owned = UniqueMmioPointer::from(foo.as_mut_slice());
806
807 assert!(!owned.ptr().is_null());
808 assert!(!owned.ptr_mut().is_null());
809
810 assert!(!owned.is_empty());
811 assert_eq!(owned.len(), 3);
812
813 let mut first: UniqueMmioPointer<ReadWrite<i32>> = owned.get(0).unwrap();
814 assert_eq!(first.read(), 1);
815
816 let mut second: UniqueMmioPointer<ReadWrite<i32>> = owned.get(1).unwrap();
817 assert_eq!(second.read(), 2);
818
819 assert!(owned.get(3).is_none());
820 }
821
822 #[test]
823 fn slice_shared() {
824 let foo = [ReadPure(1), ReadPure(2), ReadPure(3)];
825 let shared = SharedMmioPointer::from(foo.as_slice());
826
827 assert!(!shared.ptr().is_null());
828
829 assert!(!shared.is_empty());
830 assert_eq!(shared.len(), 3);
831
832 let first: SharedMmioPointer<ReadPure<i32>> = shared.get(0).unwrap();
833 assert_eq!(first.read(), 1);
834
835 let second: SharedMmioPointer<ReadPure<i32>> = shared.get(1).unwrap();
836 assert_eq!(second.read(), 2);
837
838 assert!(shared.get(3).is_none());
839
840 let second = {
843 let shared_copy = shared;
844 shared_copy.get(1).unwrap()
845 };
846 assert_eq!(second.read(), 2);
847 }
848
849 #[test]
850 fn array_field() {
851 #[repr(C)]
852 struct Regs {
853 a: [ReadPureWrite<u32>; 4],
854 }
855
856 let mut foo = Regs {
857 a: [const { ReadPureWrite(0) }; 4],
858 };
859 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
860
861 field!(owned, a).get(0).unwrap().write(42);
862 assert_eq!(field_shared!(owned, a).get(0).unwrap().read(), 42);
863 }
864
865 #[test]
866 fn slice_field() {
867 #[repr(transparent)]
868 struct Regs {
869 s: [ReadPureWrite<u32>],
870 }
871
872 impl Regs {
873 fn from_slice<'a>(slice: &'a mut [ReadPureWrite<u32>]) -> &'a mut Self {
874 let regs_ptr: *mut Self = slice as *mut [ReadPureWrite<u32>] as *mut Self;
875 unsafe { &mut *regs_ptr }
878 }
879 }
880
881 let mut foo: [ReadPureWrite<u32>; 1] = [ReadPureWrite(0)];
882 let regs_mut = Regs::from_slice(foo.as_mut_slice());
883 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(regs_mut);
884
885 field!(owned, s).get(0).unwrap().write(42);
886 assert_eq!(field_shared!(owned, s).get(0).unwrap().read(), 42);
887 }
888
889 #[test]
890 fn multiple_fields() {
891 #[repr(C)]
892 struct Regs {
893 first: ReadPureWrite<u32>,
894 second: ReadPureWrite<u32>,
895 third: ReadPureWrite<u32>,
896 }
897
898 let mut foo = Regs {
899 first: ReadPureWrite(1),
900 second: ReadPureWrite(2),
901 third: ReadPureWrite(3),
902 };
903 let mut owned: UniqueMmioPointer<Regs> = UniqueMmioPointer::from(&mut foo);
904
905 let (first, second) = unsafe { split_fields!(owned.reborrow(), first, second) };
907
908 assert_eq!(first.read(), 1);
909 assert_eq!(second.read(), 2);
910
911 drop(first);
912 drop(second);
913
914 assert_eq!(field!(owned, first).read(), 1);
915 }
916
917 #[test]
918 fn split_array() {
919 let mut foo = [ReadWrite(1), ReadWrite(2), ReadWrite(3)];
920
921 let mut parts: [UniqueMmioPointer<ReadWrite<i32>>; 3] = {
922 let owned = UniqueMmioPointer::from(&mut foo);
923
924 owned.into()
925 };
926
927 assert_eq!(parts[0].read(), 1);
928 assert_eq!(parts[1].read(), 2);
929 }
930}