1#[cfg(feature = "derive")]
20pub use peek_poke_derive::*;
21
22use core::{marker::PhantomData, mem::size_of, slice};
23use crate::{slice_ext::*, vec_ext::*};
24
25mod slice_ext;
26mod vec_ext;
27
28union MaybeUninitShim<T: Copy> {
29 uninit: (),
30 init: T,
31}
32
33pub unsafe fn peek_from_uninit<T: Copy + Peek>(bytes: *const u8) -> (T, *const u8) {
36 let mut val = MaybeUninitShim { uninit: () };
37 let bytes = <T>::peek_from(bytes, &mut val.init);
38 (val.init, bytes)
39}
40
41pub unsafe fn peek_from_default<T: Default + Peek>(bytes: *const u8) -> (T, *const u8) {
44 let mut val = T::default();
45 let bytes = <T>::peek_from(bytes, &mut val);
46 (val, bytes)
47}
48
49pub fn peek_from_slice<'a, T: Peek>(src: &'a [u8], dst: &mut T) -> &'a [u8] {
54 unsafe {
55 assert!(T::max_size() < src.len(), "WRDL: unexpected end of display list");
57 let end_ptr = T::peek_from(src.as_ptr(), dst);
58 let len = end_ptr as usize - src.as_ptr() as usize;
59 assert!(len <= src.len(), "WRDL: Peek::max_size was wrong");
62 slice::from_raw_parts(end_ptr, src.len() - len)
63 }
64}
65
66pub fn poke_inplace_slice<T: Poke>(src: &T, dst: &mut [u8]) {
68 assert!(T::max_size() <= dst.len(), "WRDL: buffer too small to write into");
69 unsafe {
70 src.poke_into(dst.as_mut_ptr());
71 }
72}
73
74pub fn poke_into_vec<T: Poke>(src: &T, dst: &mut Vec<u8>) {
76 dst.reserve(T::max_size());
77 unsafe {
78 let ptr = dst.as_end_mut_ptr();
79 let end_ptr = src.poke_into(ptr);
80 dst.set_end_ptr(end_ptr);
81 }
82}
83
84pub fn poke_extend_vec<I>(src: I, dst: &mut Vec<u8>) -> usize
86where
87 I: ExactSizeIterator,
88 I::Item: Poke,
89{
90 let len = src.len();
91 let max_size = len * I::Item::max_size();
92 dst.reserve(max_size);
93 unsafe {
94 let ptr = dst.as_end_mut_ptr();
95 let end_ptr = src.take(len).fold(ptr, |ptr, item| item.poke_into(ptr));
98 dst.set_end_ptr(end_ptr);
99 }
100
101 len
102}
103
104pub fn ensure_red_zone<T: Poke>(bytes: &mut Vec<u8>) {
108 bytes.reserve(T::max_size());
109 unsafe {
110 let end_ptr = bytes.as_end_mut_ptr();
111 end_ptr.write_bytes(0, T::max_size());
112 bytes.set_end_ptr(end_ptr.add(T::max_size()));
113 }
114}
115
116#[inline]
117unsafe fn read_verbatim<T>(src: *const u8, dst: *mut T) -> *const u8 {
118 *dst = (src as *const T).read_unaligned();
119 src.add(size_of::<T>())
120}
121
122#[inline]
123unsafe fn write_verbatim<T>(src: T, dst: *mut u8) -> *mut u8 {
124 (dst as *mut T).write_unaligned(src);
125 dst.add(size_of::<T>())
126}
127
128#[cfg(feature = "extras")]
129mod euclid;
130
131pub unsafe trait Poke {
165 fn max_size() -> usize;
174 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8;
188}
189
190pub trait Peek: Poke {
223 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8;
238}
239
240macro_rules! impl_poke_for_deref {
241 (<$($desc:tt)+) => {
242 unsafe impl <$($desc)+ {
243 #[inline(always)]
244 fn max_size() -> usize {
245 <T>::max_size()
246 }
247 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
248 (**self).poke_into(bytes)
249 }
250 }
251 }
252}
253
254impl_poke_for_deref!(<'a, T: Poke> Poke for &'a T);
255impl_poke_for_deref!(<'a, T: Poke> Poke for &'a mut T);
256
257macro_rules! impl_for_primitive {
258 ($($ty:ty)+) => {
259 $(unsafe impl Poke for $ty {
260 #[inline(always)]
261 fn max_size() -> usize {
262 size_of::<Self>()
263 }
264 #[inline(always)]
265 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
266 write_verbatim(*self, bytes)
267 }
268 }
269 impl Peek for $ty {
270 #[inline(always)]
271 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
272 read_verbatim(bytes, output)
273 }
274 })+
275 };
276}
277
278impl_for_primitive! {
279 i8 i16 i32 i64 isize
280 u8 u16 u32 u64 usize
281 f32 f64
282}
283
284unsafe impl Poke for bool {
285 #[inline(always)]
286 fn max_size() -> usize {
287 u8::max_size()
288 }
289 #[inline]
290 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
291 (*self as u8).poke_into(bytes)
292 }
293}
294
295impl Peek for bool {
296 #[inline]
297 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
298 let mut int_bool = 0u8;
299 let ptr = <u8>::peek_from(bytes, &mut int_bool);
300 *output = int_bool != 0;
301 ptr
302 }
303}
304
305unsafe impl<T> Poke for PhantomData<T> {
306 #[inline(always)]
307 fn max_size() -> usize {
308 0
309 }
310 #[inline(always)]
311 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
312 bytes
313 }
314}
315
316impl<T> Peek for PhantomData<T> {
317 #[inline(always)]
318 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
319 *output = PhantomData;
320 bytes
321 }
322}
323
324unsafe impl<T: Poke> Poke for Option<T> {
325 #[inline(always)]
326 fn max_size() -> usize {
327 u8::max_size() + T::max_size()
328 }
329
330 #[inline]
331 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
332 match self {
333 None => 0u8.poke_into(bytes),
334 Some(ref v) => {
335 let bytes = 1u8.poke_into(bytes);
336 let bytes = v.poke_into(bytes);
337 bytes
338 }
339 }
340 }
341}
342
343impl<T: Default + Peek> Peek for Option<T> {
344 #[inline]
345 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
346 let (variant, bytes) = peek_from_default::<u8>(bytes);
347 match variant {
348 0 => {
349 *output = None;
350 bytes
351 }
352 1 => {
353 let (val, bytes) = peek_from_default(bytes);
354 *output = Some(val);
355 bytes
356 }
357 _ => unreachable!(),
358 }
359 }
360}
361
362macro_rules! impl_for_arrays {
363 ($($len:tt)+) => {
364 $(unsafe impl<T: Poke> Poke for [T; $len] {
365 fn max_size() -> usize {
366 $len * T::max_size()
367 }
368 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
369 self.iter().fold(bytes, |bytes, e| e.poke_into(bytes))
370 }
371 }
372 impl<T: Peek> Peek for [T; $len] {
373 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
374 (&mut *output).iter_mut().fold(bytes, |bytes, e| <T>::peek_from(bytes, e))
375 }
376 })+
377 }
378}
379
380impl_for_arrays! {
381 01 02 03 04 05 06 07 08 09 10
382 11 12 13 14 15 16 17 18 19 20
383 21 22 23 24 25 26 27 28 29 30
384 31 32
385}
386
387unsafe impl Poke for () {
388 fn max_size() -> usize {
389 0
390 }
391 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
392 bytes
393 }
394}
395impl Peek for () {
396 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
397 *output = ();
398 bytes
399 }
400}
401
402macro_rules! impl_for_tuple {
403 ($($n:tt: $ty:ident),+) => {
404 unsafe impl<$($ty: Poke),+> Poke for ($($ty,)+) {
405 #[inline(always)]
406 fn max_size() -> usize {
407 0 $(+ <$ty>::max_size())+
408 }
409 unsafe fn poke_into(&self, bytes: *mut u8) -> *mut u8 {
410 $(let bytes = self.$n.poke_into(bytes);)+
411 bytes
412 }
413 }
414 impl<$($ty: Peek),+> Peek for ($($ty,)+) {
415 unsafe fn peek_from(bytes: *const u8, output: *mut Self) -> *const u8 {
416 $(let bytes = $ty::peek_from(bytes, &mut (*output).$n);)+
417 bytes
418 }
419 }
420 }
421}
422
423impl_for_tuple!(0: A);
424impl_for_tuple!(0: A, 1: B);
425impl_for_tuple!(0: A, 1: B, 2: C);
426impl_for_tuple!(0: A, 1: B, 2: C, 3: D);
427impl_for_tuple!(0: A, 1: B, 2: C, 3: D, 4: E);