untyped_bytes/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::{
    borrow::Borrow,
    mem::{self, MaybeUninit},
    slice,
};

#[derive(Clone, Debug, Default)]
pub struct UntypedBytes {
    bytes: Vec<u8>,
}

// unsafe to inspect the bytes after casting
#[inline]
unsafe fn as_bytes<T: Copy + Send + Sync + 'static>(value: &T) -> &[u8] {
    slice::from_raw_parts(value as *const T as _, mem::size_of::<T>())
}

// unsafe to inspect the bytes after casting
#[inline]
unsafe fn as_bytes_slice<T: Copy + Send + Sync + 'static>(value: &[T]) -> &[u8] {
    slice::from_raw_parts(value.as_ptr() as _, mem::size_of_val(value))
}

impl UntypedBytes {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            bytes: Vec::with_capacity(capacity),
        }
    }

    /// Effectively a `mem::transmute`.
    pub fn from_vec<T: Copy + 'static>(mut value: Vec<T>) -> Self {
        let size = mem::size_of::<T>();
        let bytes = unsafe {
            Vec::from_raw_parts(
                value.as_mut_ptr() as _,
                value.len() * size,
                value.capacity() * size,
            )
        };
        mem::forget(value);
        Self { bytes }
    }

    pub fn from_slice<T, V>(value: V) -> Self
    where
        T: Copy + Send + Sync + 'static,
        V: Borrow<[T]>,
    {
        let borrowed = value.borrow();
        let mut result = Self::with_capacity(mem::size_of_val(borrowed));
        let raw = unsafe { as_bytes_slice(borrowed) };
        result.bytes.extend(raw);
        result
    }

    pub fn is_empty(&self) -> bool {
        self.bytes.is_empty()
    }

    pub fn len(&self) -> usize {
        self.bytes.len()
    }

    pub fn clear(&mut self) {
        self.bytes.clear()
    }

    pub fn push<T: Copy + Send + Sync + 'static>(&mut self, value: T) {
        let raw = unsafe { as_bytes(&value) };
        self.bytes.extend(raw)
    }

    #[inline]
    pub fn extend_from_slice<T, V>(&mut self, value: V)
    where
        T: Copy + Send + Sync + 'static,
        V: Borrow<[T]>,
    {
        let raw = unsafe { as_bytes_slice(value.borrow()) };
        self.bytes.extend_from_slice(raw)
    }

    /// Returns a slice that is unsafe to inspect in the presence of padding bytes, but is safe to
    /// `memcpy`. Additionally, alignment of the returned slice is the same as
    /// `mem::align_of::<u8>()`.
    pub unsafe fn as_slice(&self) -> &[u8] {
        &self.bytes
    }

    /// Casts the backing bytes to a value of type `T`. This is only safe the backing bytes were
    /// created from a value of type `T`.
    pub unsafe fn cast<T: Copy + Send + Sync + 'static>(&self) -> T {
        debug_assert_eq!(
            mem::size_of::<T>(),
            self.len(),
            "Attempt to cast `UntypedBytes` to a value of a different size"
        );
        let mut result = MaybeUninit::uninit();
        self.as_slice()
            .as_ptr()
            .copy_to_nonoverlapping(result.as_mut_ptr() as *mut u8, mem::size_of::<T>());
        result.assume_init()
    }
}

impl<T: Copy + Send + Sync + 'static> From<T> for UntypedBytes {
    fn from(value: T) -> Self {
        Self::from_vec(vec![value])
    }
}

impl<A: Copy + Send + Sync + 'static> Extend<A> for UntypedBytes {
    #[inline]
    fn extend<T: IntoIterator<Item = A>>(&mut self, value: T) {
        if std::any::type_name::<T>()
            == std::any::type_name::<std::iter::Copied<std::slice::Iter<'_, A>>>()
        {
            let raw = unsafe { mem::transmute_copy::<_, std::slice::Iter<'_, A>>(&value) };
            self.extend_from_slice(raw.as_slice())
        } else if std::any::type_name::<T>()
            == std::any::type_name::<std::iter::Cloned<std::slice::Iter<'_, A>>>()
        {
            let raw = unsafe { mem::transmute_copy::<_, std::slice::Iter<'_, A>>(&value) };
            self.extend_from_slice(raw.as_slice())
        } else if std::any::type_name::<T>()
            == std::any::type_name::<std::iter::Copied<std::slice::IterMut<'_, A>>>()
        {
            let raw = unsafe { mem::transmute_copy::<_, std::slice::IterMut<'_, A>>(&value) };
            self.extend_from_slice(raw.into_slice())
        } else if std::any::type_name::<T>()
            == std::any::type_name::<std::iter::Cloned<std::slice::IterMut<'_, A>>>()
        {
            let raw = unsafe { mem::transmute_copy::<_, std::slice::IterMut<'_, A>>(&value) };
            self.extend_from_slice(raw.into_slice())
        } else if std::any::type_name::<T>() == std::any::type_name::<std::vec::IntoIter<A>>() {
            let raw = unsafe { mem::transmute_copy::<_, std::vec::IntoIter<A>>(&value) };
            std::mem::forget(value);
            self.extend_from_slice(raw.as_slice())
        } else if std::any::type_name::<T>() == std::any::type_name::<Vec<A>>() {
            let raw = unsafe { mem::transmute_copy::<_, Vec<A>>(&value) };
            std::mem::forget(value);
            self.extend_from_slice(raw.as_slice())
        } else {
            for elem in value {
                self.push(elem)
            }
        }
    }
}