resource_table/
types.rs

1#[repr(C)]
2#[derive(Clone, Debug)]
3pub struct Header<const N: usize> {
4    pub ver: u32,
5    pub num: u32,
6    pub reserved: [u32; 2],
7    pub offset: [u32; N],
8}
9
10impl<const N: usize> Header<N> {
11    pub const fn new(offset: [u32; N]) -> Self {
12        Self {
13            ver: 1,
14            num: N as u32,
15            reserved: [0; _],
16            offset,
17        }
18    }
19}
20
21#[repr(C)]
22#[derive(Clone, Debug)]
23pub struct Resource<T> {
24    pub type_: u32,
25    pub data: T,
26}
27
28pub trait ResourceType {
29    const RESOURCE_TYPE: u32;
30}
31
32impl<T> Resource<T>
33where
34    T: ResourceType,
35{
36    pub const fn new(data: T) -> Self {
37        Self {
38            type_: T::RESOURCE_TYPE,
39            data,
40        }
41    }
42}
43
44/// Device address representation.
45///
46/// Device address fields in the resource table are commonly filled
47/// with pointer values that aren't known until link time. In Rust,
48/// this is only possible using actual pointer types, but the resource
49/// table pointer fields are a fixed 32 bits.
50///
51/// In order for this crate to be useful on 64-bit platforms, device
52/// addresses are represented using this union. It always contains a
53/// `raw` integer field, and on systems with 32-bit pointers, it also
54/// contains a `ptr` field.
55#[repr(C)]
56#[derive(Clone, Copy)]
57pub union DevAddr {
58    /// Raw address.
59    pub raw: u32,
60    /// Pointer address (only on 32-bit platforms).
61    #[cfg(target_pointer_width = "32")]
62    pub ptr: *mut u8,
63}
64
65/// Pointers are not sync, but we necessarily need pointers stored in
66/// statics.
67unsafe impl Sync for DevAddr {}
68
69impl core::fmt::Debug for DevAddr {
70    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
71        unsafe { write!(f, "{:#x?}", self.raw) }
72    }
73}
74
75impl DevAddr {
76    /// Create a device address from a raw integer.
77    pub const fn from_u32(raw: u32) -> Self {
78        Self { raw }
79    }
80
81    /// Create a device address from a pointer (only on 32-bit platforms).
82    #[cfg(target_pointer_width = "32")]
83    pub const fn const_from_ptr(ptr: *mut u8) -> Self {
84        Self { ptr }
85    }
86
87    /// Create a device address from a pointer.
88    pub fn from_ptr(ptr: *mut u8) -> Self {
89        #[cfg(target_pointer_width = "32")]
90        return Self { ptr };
91
92        #[cfg(not(target_pointer_width = "32"))]
93        return Self { raw: ptr as u32 };
94    }
95
96    /// Get the device address as a raw integer.
97    pub fn as_u32(&self) -> u32 {
98        unsafe { self.raw }
99    }
100
101    /// Get the device address as a pointer.
102    pub fn as_ptr(&self) -> *mut u8 {
103        #[cfg(target_pointer_width = "32")]
104        unsafe {
105            self.ptr
106        }
107
108        #[cfg(not(target_pointer_width = "32"))]
109        unsafe {
110            self.raw as *mut u8
111        }
112    }
113}
114
115/// Device memory area representation.
116///
117/// This is a [DevAddr] paired with a length, representing an area in
118/// device memory.
119#[repr(C)]
120#[derive(Clone, Copy, Debug)]
121pub struct DevArea {
122    /// Base address of buffer.
123    pub addr: DevAddr,
124    /// Length of buffer, in bytes.
125    pub len: usize,
126}
127
128impl DevArea {
129    /// Create a device area from a raw integer and length.
130    pub const fn from_u32_len(raw: u32, len: usize) -> Self {
131        Self {
132            addr: DevAddr::from_u32(raw),
133            len,
134        }
135    }
136
137    /// Create a device area from a slice pointer (only on 32-bit
138    /// platforms).
139    #[cfg(target_pointer_width = "32")]
140    pub const fn const_from_slice(ptr: *mut [u8]) -> Self {
141        Self {
142            addr: DevAddr::const_from_ptr(ptr as *mut u8),
143            len: ptr.len(),
144        }
145    }
146
147    /// Create a device area from a slice pointer.
148    pub fn from_slice(ptr: *mut [u8]) -> Self {
149        Self {
150            addr: DevAddr::from_ptr(ptr as *mut u8),
151            len: ptr.len(),
152        }
153    }
154
155    /// Create a device area from a base pointer and length (only on
156    /// 32-bit platforms).
157    #[cfg(target_pointer_width = "32")]
158    pub const fn const_from_ptr_len(ptr: *mut u8, len: usize) -> Self {
159        Self {
160            addr: DevAddr::const_from_ptr(ptr),
161            len,
162        }
163    }
164
165    /// Create a device area from a base pointer and length.
166    pub fn from_ptr_len(ptr: *mut u8, len: usize) -> Self {
167        Self {
168            addr: DevAddr::from_ptr(ptr),
169            len,
170        }
171    }
172}
173
174/// Resource entry wrapper.
175///
176/// Resources created by the [resource_table!](crate::resource_table!)
177/// macro are wrapped in this struct, and it dereferences to the
178/// original type. This is an implementation detail to prevent Rust
179/// from aggressively optimizing away memory reads.
180pub struct Handle<T> {
181    inner: *mut T,
182}
183
184unsafe impl<T> Sync for Handle<T> where T: Sync {}
185
186impl<T> Handle<T> {
187    // used by the macro, not a public API
188    #[doc(hidden)]
189    pub const fn new(inner: *mut T) -> Self {
190        Self { inner }
191    }
192}
193
194impl<T> core::ops::Deref for Handle<T> {
195    type Target = T;
196
197    fn deref(&self) -> &Self::Target {
198        // safety: we hold the *mut T, and never hand it out mutably
199        unsafe { self.inner.as_ref().unwrap() }
200    }
201}