untyped_bytes/
lib.rs

1use std::{
2    borrow::Borrow,
3    mem::{self, MaybeUninit},
4    slice,
5};
6
7#[derive(Clone, Debug, Default)]
8pub struct UntypedBytes {
9    bytes: Vec<u8>,
10}
11
12// unsafe to inspect the bytes after casting
13#[inline]
14unsafe fn as_bytes<T: Copy + Send + Sync + 'static>(value: &T) -> &[u8] {
15    slice::from_raw_parts(value as *const T as _, mem::size_of::<T>())
16}
17
18// unsafe to inspect the bytes after casting
19#[inline]
20unsafe fn as_bytes_slice<T: Copy + Send + Sync + 'static>(value: &[T]) -> &[u8] {
21    slice::from_raw_parts(value.as_ptr() as _, mem::size_of_val(value))
22}
23
24impl UntypedBytes {
25    pub fn new() -> Self {
26        Default::default()
27    }
28
29    pub fn with_capacity(capacity: usize) -> Self {
30        Self {
31            bytes: Vec::with_capacity(capacity),
32        }
33    }
34
35    /// Effectively a `mem::transmute`.
36    pub fn from_vec<T: Copy + 'static>(mut value: Vec<T>) -> Self {
37        let size = mem::size_of::<T>();
38        let bytes = unsafe {
39            Vec::from_raw_parts(
40                value.as_mut_ptr() as _,
41                value.len() * size,
42                value.capacity() * size,
43            )
44        };
45        mem::forget(value);
46        Self { bytes }
47    }
48
49    pub fn from_slice<T, V>(value: V) -> Self
50    where
51        T: Copy + Send + Sync + 'static,
52        V: Borrow<[T]>,
53    {
54        let borrowed = value.borrow();
55        let mut result = Self::with_capacity(mem::size_of_val(borrowed));
56        let raw = unsafe { as_bytes_slice(borrowed) };
57        result.bytes.extend(raw);
58        result
59    }
60
61    pub fn is_empty(&self) -> bool {
62        self.bytes.is_empty()
63    }
64
65    pub fn len(&self) -> usize {
66        self.bytes.len()
67    }
68
69    pub fn clear(&mut self) {
70        self.bytes.clear()
71    }
72
73    pub fn push<T: Copy + Send + Sync + 'static>(&mut self, value: T) {
74        let raw = unsafe { as_bytes(&value) };
75        self.bytes.extend(raw)
76    }
77
78    #[inline]
79    pub fn extend_from_slice<T, V>(&mut self, value: V)
80    where
81        T: Copy + Send + Sync + 'static,
82        V: Borrow<[T]>,
83    {
84        let raw = unsafe { as_bytes_slice(value.borrow()) };
85        self.bytes.extend_from_slice(raw)
86    }
87
88    /// Returns a slice that is unsafe to inspect in the presence of padding bytes, but is safe to
89    /// `memcpy`. Additionally, alignment of the returned slice is the same as
90    /// `mem::align_of::<u8>()`.
91    pub unsafe fn as_slice(&self) -> &[u8] {
92        &self.bytes
93    }
94
95    /// Casts the backing bytes to a value of type `T`. This is only safe the backing bytes were
96    /// created from a value of type `T`.
97    pub unsafe fn cast<T: Copy + Send + Sync + 'static>(&self) -> T {
98        debug_assert_eq!(
99            mem::size_of::<T>(),
100            self.len(),
101            "Attempt to cast `UntypedBytes` to a value of a different size"
102        );
103        let mut result = MaybeUninit::uninit();
104        self.as_slice()
105            .as_ptr()
106            .copy_to_nonoverlapping(result.as_mut_ptr() as *mut u8, mem::size_of::<T>());
107        result.assume_init()
108    }
109}
110
111impl<T: Copy + Send + Sync + 'static> From<T> for UntypedBytes {
112    fn from(value: T) -> Self {
113        Self::from_vec(vec![value])
114    }
115}
116
117impl<A: Copy + Send + Sync + 'static> Extend<A> for UntypedBytes {
118    #[inline]
119    fn extend<T: IntoIterator<Item = A>>(&mut self, value: T) {
120        if std::any::type_name::<T>()
121            == std::any::type_name::<std::iter::Copied<std::slice::Iter<'_, A>>>()
122        {
123            let raw = unsafe { mem::transmute_copy::<_, std::slice::Iter<'_, A>>(&value) };
124            self.extend_from_slice(raw.as_slice())
125        } else if std::any::type_name::<T>()
126            == std::any::type_name::<std::iter::Cloned<std::slice::Iter<'_, A>>>()
127        {
128            let raw = unsafe { mem::transmute_copy::<_, std::slice::Iter<'_, A>>(&value) };
129            self.extend_from_slice(raw.as_slice())
130        } else if std::any::type_name::<T>()
131            == std::any::type_name::<std::iter::Copied<std::slice::IterMut<'_, A>>>()
132        {
133            let raw = unsafe { mem::transmute_copy::<_, std::slice::IterMut<'_, A>>(&value) };
134            self.extend_from_slice(raw.into_slice())
135        } else if std::any::type_name::<T>()
136            == std::any::type_name::<std::iter::Cloned<std::slice::IterMut<'_, A>>>()
137        {
138            let raw = unsafe { mem::transmute_copy::<_, std::slice::IterMut<'_, A>>(&value) };
139            self.extend_from_slice(raw.into_slice())
140        } else if std::any::type_name::<T>() == std::any::type_name::<std::vec::IntoIter<A>>() {
141            let raw = unsafe { mem::transmute_copy::<_, std::vec::IntoIter<A>>(&value) };
142            std::mem::forget(value);
143            self.extend_from_slice(raw.as_slice())
144        } else if std::any::type_name::<T>() == std::any::type_name::<Vec<A>>() {
145            let raw = unsafe { mem::transmute_copy::<_, Vec<A>>(&value) };
146            std::mem::forget(value);
147            self.extend_from_slice(raw.as_slice())
148        } else {
149            for elem in value {
150                self.push(elem)
151            }
152        }
153    }
154}