@@ -14,32 +14,41 @@ use core::mem::MaybeUninit;
1414///
1515/// # Safety
1616///
17- /// Implementers must ensure that:
18- /// - `Self` is layout-compatible with [`RawDeviceId::RawType`]; i.e. it's safe to transmute to
19- /// `RawDeviceId`.
17+ /// Implementers must ensure that `Self` is layout-compatible with [`RawDeviceId::RawType`];
18+ /// i.e. it's safe to transmute to `RawDeviceId`.
2019///
21- /// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building
22- /// the ID table.
20+ /// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building
21+ /// the ID table.
2322///
24- /// Ideally, this should be achieved using a const function that does conversion instead of
25- /// transmute; however, const trait functions relies on `const_trait_impl` unstable feature,
26- /// which is broken/gone in Rust 1.73.
27- ///
28- /// - `DRIVER_DATA_OFFSET` is the offset of context/data field of the device ID (usually named
29- /// `driver_data`) of the device ID, the field is suitable sized to write a `usize` value.
30- ///
31- /// Similar to the previous requirement, the data should ideally be added during `Self` to
32- /// `RawType` conversion, but there's currently no way to do it when using traits in const.
23+ /// Ideally, this should be achieved using a const function that does conversion instead of
24+ /// transmute; however, const trait functions relies on `const_trait_impl` unstable feature,
25+ /// which is broken/gone in Rust 1.73.
3326pub unsafe trait RawDeviceId {
3427 /// The raw type that holds the device id.
3528 ///
3629 /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
3730 type RawType : Copy ;
31+ }
3832
39- /// The offset to the context/data field.
33+ /// Extension trait for [`RawDeviceId`] for devices that embed an index or context value.
34+ ///
35+ /// This is typically used when the device ID struct includes a field like `driver_data`
36+ /// that is used to store a pointer-sized value (e.g., an index or context pointer).
37+ ///
38+ /// # Safety
39+ ///
40+ /// Implementers must ensure that `DRIVER_DATA_OFFSET` is the correct offset (in bytes) to
41+ /// the context/data field (e.g., the `driver_data` field) within the raw device ID structure.
42+ /// This field must be correctly sized to hold a `usize`.
43+ ///
44+ /// Ideally, the data should be added during `Self` to `RawType` conversion,
45+ /// but there's currently no way to do it when using traits in const.
46+ pub unsafe trait RawDeviceIdIndex : RawDeviceId {
47+ /// The offset (in bytes) to the context/data field in the raw device ID.
4048 const DRIVER_DATA_OFFSET : usize ;
4149
42- /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceId`] trait.
50+ /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceIdIndex`]
51+ /// trait.
4352 fn index ( & self ) -> usize ;
4453}
4554
@@ -68,7 +77,15 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
6877 /// Creates a new instance of the array.
6978 ///
7079 /// The contents are derived from the given identifiers and context information.
71- pub const fn new ( ids : [ ( T , U ) ; N ] ) -> Self {
80+ ///
81+ /// # Safety
82+ ///
83+ /// `data_offset` as `None` is always safe.
84+ /// If `data_offset` is `Some(data_offset)`, then:
85+ /// - `data_offset` must be the correct offset (in bytes) to the context/data field
86+ /// (e.g., the `driver_data` field) within the raw device ID structure.
87+ /// - The field at `data_offset` must be correctly sized to hold a `usize`.
88+ const unsafe fn build ( ids : [ ( T , U ) ; N ] , data_offset : Option < usize > ) -> Self {
7289 let mut raw_ids = [ const { MaybeUninit :: < T :: RawType > :: uninit ( ) } ; N ] ;
7390 let mut infos = [ const { MaybeUninit :: uninit ( ) } ; N ] ;
7491
@@ -77,14 +94,16 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
7794 // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is
7895 // layout-wise compatible with `RawType`.
7996 raw_ids[ i] = unsafe { core:: mem:: transmute_copy ( & ids[ i] . 0 ) } ;
80- // SAFETY: by the safety requirement of `RawDeviceId`, this would be effectively
81- // `raw_ids[i].driver_data = i;`.
82- unsafe {
83- raw_ids[ i]
84- . as_mut_ptr ( )
85- . byte_offset ( T :: DRIVER_DATA_OFFSET as _ )
86- . cast :: < usize > ( )
87- . write ( i) ;
97+ if let Some ( data_offset) = data_offset {
98+ // SAFETY: by the safety requirement of this function, this would be effectively
99+ // `raw_ids[i].driver_data = i;`.
100+ unsafe {
101+ raw_ids[ i]
102+ . as_mut_ptr ( )
103+ . byte_offset ( data_offset as _ )
104+ . cast :: < usize > ( )
105+ . write ( i) ;
106+ }
88107 }
89108
90109 // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
@@ -109,12 +128,34 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
109128 }
110129 }
111130
131+ /// Creates a new instance of the array without writing index values.
132+ ///
133+ /// The contents are derived from the given identifiers and context information.
134+ /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
135+ pub const fn new_without_index ( ids : [ ( T , U ) ; N ] ) -> Self {
136+ // SAFETY: Calling `Self::build` with `offset = None` is always safe,
137+ // because no raw memory writes are performed in this case.
138+ unsafe { Self :: build ( ids, None ) }
139+ }
140+
112141 /// Reference to the contained [`RawIdArray`].
113142 pub const fn raw_ids ( & self ) -> & RawIdArray < T , N > {
114143 & self . raw_ids
115144 }
116145}
117146
147+ impl < T : RawDeviceId + RawDeviceIdIndex , U , const N : usize > IdArray < T , U , N > {
148+ /// Creates a new instance of the array.
149+ ///
150+ /// The contents are derived from the given identifiers and context information.
151+ pub const fn new ( ids : [ ( T , U ) ; N ] ) -> Self {
152+ // SAFETY: by the safety requirement of `RawDeviceIdIndex`,
153+ // `T::DRIVER_DATA_OFFSET` is guaranteed to be the correct offset (in bytes) to
154+ // a field within `T::RawType`.
155+ unsafe { Self :: build ( ids, Some ( T :: DRIVER_DATA_OFFSET ) ) }
156+ }
157+ }
158+
118159/// A device id table.
119160///
120161/// This trait is only implemented by `IdArray`.
0 commit comments