dataview/lib.rs
1/*!
2The [`Pod` trait](Pod) marks types whose values can be safely transmuted between byte arrays of the same size.
3
4The [`DataView` type](DataView) defines read and write data APIs to an underlying byte buffer.
5
6# Examples
7
8```
9#[derive(dataview::Pod)]
10#[repr(C)]
11struct MyType {
12 field: i32,
13}
14
15// Construct a zero initialized instance
16let mut inst: MyType = dataview::zeroed();
17assert_eq!(inst.field, 0);
18
19// Use DataView to access the instance
20let view = dataview::DataView::from_mut(&mut inst);
21view.write(2, &255_u8);
22
23// Create a byte view over the instance
24assert_eq!(dataview::bytes(&inst), &[0, 0, 255, 0]);
25```
26*/
27
28#![no_std]
29
30use core::{mem, slice};
31use core::marker::PhantomData;
32
33mod data_view;
34pub use self::data_view::DataView;
35
36#[cfg(feature = "derive_pod")]
37#[doc(inline)]
38pub use ::derive_pod::Pod;
39
40#[cfg(feature = "derive_pod")]
41#[doc(hidden)]
42pub use ::derive_pod::FieldOffsets;
43
44mod derive_pod;
45mod field_offsets;
46mod offset_of;
47
48#[macro_use]
49mod embed;
50
51/// Types whose values can be safely transmuted between byte arrays of the same size.
52///
53/// # Safety
54///
55/// It must be safe to transmute between any byte array (with length equal to the size of the type) and `Self`.
56///
57/// This is true for these primitive types: `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, `u128`, `f32`, `f64`.
58/// The raw pointer types are not pod under strict provenance rules but can be through the 'int2ptr' feature.
59/// Primitives such as `str` and `bool` are not pod because not every valid byte pattern is a valid instance of these types.
60/// References or types with lifetimes are _never_ pod.
61///
62/// Arrays and slices of pod types are also pod themselves.
63///
64/// Note that it is legal for pod types to be a [ZST](https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts).
65///
66/// When `Pod` is implemented for a user defined type it must meet the following requirements:
67///
68/// * Must be annotated with [`#[repr(C)]`](https://doc.rust-lang.org/nomicon/other-reprs.html#reprc)
69/// or [`#[repr(transparent)]`](https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent).
70/// * Must have every field's type implement `Pod` itself.
71/// * Must not have any padding between its fields, define dummy fields to cover the padding.
72///
73/// # Derive macro
74///
75/// To help with safely implementing this trait for user defined types, a [derive macro](derive@Pod) is provided to implement the `Pod` trait if the requirements are satisfied.
76pub unsafe trait Pod: 'static {}
77
78/// Returns a zero-initialized instance of the type.
79///
80/// ```
81/// let v: i32 = dataview::zeroed();
82/// assert_eq!(v, 0);
83/// ```
84#[inline]
85pub fn zeroed<T: Pod>() -> T {
86 unsafe { mem::MaybeUninit::zeroed().assume_init() }
87}
88
89/// Returns the object's memory as a byte slice.
90///
91/// ```
92/// let v = 0xcdcdcdcd_u32;
93/// assert_eq!(dataview::bytes(&v), &[0xcd, 0xcd, 0xcd, 0xcd]);
94/// ```
95#[inline]
96pub fn bytes<T: ?Sized + Pod>(src: &T) -> &[u8] {
97 unsafe { slice::from_raw_parts(src as *const _ as *const u8, mem::size_of_val(src)) }
98}
99
100/// Returns the object's memory as a mutable byte slice.
101#[inline]
102pub fn bytes_mut<T: ?Sized + Pod>(src: &mut T) -> &mut [u8] {
103 unsafe { slice::from_raw_parts_mut(src as *mut _ as *mut u8, mem::size_of_val(src)) }
104}
105
106/// Helper trait to provide methods directly on the pod types.
107///
108/// Do not use this trait in any signatures, use [`Pod`] directly instead.
109/// There's a blanket impl that provides these methods for all pod types.
110pub trait PodMethods {
111 /// Returns a zero-initialized instance of the type.
112 fn zeroed() -> Self where Self: Sized;
113 /// Returns the object's memory as a byte slice.
114 fn as_bytes(&self) -> &[u8];
115 /// Returns the object's memory as a mutable byte slice.
116 fn as_bytes_mut(&mut self) -> &mut [u8];
117 /// Returns a data view into the object's memory.
118 fn as_data_view(&self) -> &DataView;
119 /// Returns a mutable data view into the object's memory.
120 fn as_data_view_mut(&mut self) -> &mut DataView;
121}
122
123impl<T: ?Sized + Pod> PodMethods for T {
124 #[inline]
125 fn zeroed() -> T where T: Sized {
126 zeroed()
127 }
128 #[inline]
129 fn as_bytes(&self) -> &[u8] {
130 bytes(self)
131 }
132 #[inline]
133 fn as_bytes_mut(&mut self) -> &mut [u8] {
134 bytes_mut(self)
135 }
136 #[inline]
137 fn as_data_view(&self) -> &DataView {
138 DataView::from(self)
139 }
140 #[inline]
141 fn as_data_view_mut(&mut self) -> &mut DataView {
142 DataView::from_mut(self)
143 }
144}
145
146unsafe impl Pod for () {}
147
148unsafe impl Pod for i8 {}
149unsafe impl Pod for i16 {}
150unsafe impl Pod for i32 {}
151unsafe impl Pod for i64 {}
152unsafe impl Pod for i128 {}
153unsafe impl Pod for isize {}
154
155unsafe impl Pod for u8 {}
156unsafe impl Pod for u16 {}
157unsafe impl Pod for u32 {}
158unsafe impl Pod for u64 {}
159unsafe impl Pod for u128 {}
160unsafe impl Pod for usize {}
161
162unsafe impl Pod for f32 {}
163unsafe impl Pod for f64 {}
164
165#[cfg(feature = "int2ptr")]
166unsafe impl<T: 'static> Pod for *const T {}
167#[cfg(feature = "int2ptr")]
168unsafe impl<T: 'static> Pod for *mut T {}
169
170unsafe impl<T: 'static> Pod for PhantomData<T> {}
171
172unsafe impl<T: Pod> Pod for [T] {}
173unsafe impl<T: Pod, const N: usize> Pod for [T; N] {}
174
175// Strict provenance approved way of checking raw pointer alignment without exposing the pointer
176fn is_aligned<T>(ptr: *const T) -> bool {
177 let addr: usize = ptr.addr();
178 addr % mem::align_of::<T>() == 0
179}
180
181#[cfg(test)]
182mod tests;
183
184#[cfg(doc)]
185#[doc = include_str!("../readme.md")]
186fn readme() {}
187
188/// Reveals the evaluated value of a constant expression.
189///
190/// The result is a compiletime error: `expected an array with a fixed size of 0 elements, found one with N elements` where `N` is the value of the constant expression.
191///
192/// ```compile_fail
193/// struct Foo {
194/// field1: i8,
195/// field2: u16,
196/// }
197///
198/// dataview::reveal_const!(std::mem::size_of::<Foo>());
199/// ```
200#[doc(hidden)]
201#[macro_export]
202macro_rules! reveal_const {
203 ($e:expr) => {
204 const _: [(); 0] = [(); $e];
205 };
206}