spirv_tools/
binary.rs

1#[cfg(feature = "use-compiled-tools")]
2pub mod external {
3    use spirv_tools_sys::shared;
4
5    pub struct ExternalBinary {
6        inner: *mut shared::Binary,
7    }
8
9    impl ExternalBinary {
10        #[inline]
11        pub(crate) fn new(bin: *mut shared::Binary) -> Self {
12            Self { inner: bin }
13        }
14    }
15
16    impl AsRef<[u32]> for ExternalBinary {
17        #[inline]
18        fn as_ref(&self) -> &[u32] {
19            unsafe { std::slice::from_raw_parts((*self.inner).code, (*self.inner).size) }
20        }
21    }
22
23    impl AsRef<[u8]> for ExternalBinary {
24        #[inline]
25        fn as_ref(&self) -> &[u8] {
26            unsafe {
27                std::slice::from_raw_parts(
28                    (*self.inner).code.cast(),
29                    (*self.inner).size * size_of::<u32>(),
30                )
31            }
32        }
33    }
34
35    impl Drop for ExternalBinary {
36        #[inline]
37        fn drop(&mut self) {
38            unsafe {
39                shared::binary_destroy(self.inner);
40            }
41        }
42    }
43}
44
45pub enum Binary {
46    #[cfg(feature = "use-compiled-tools")]
47    External(external::ExternalBinary),
48    OwnedU32(Vec<u32>),
49    OwnedU8(Vec<u8>),
50}
51
52impl Binary {
53    /// Gets a byte array for binary
54    #[inline]
55    pub fn as_bytes(&self) -> &[u8] {
56        self.as_ref()
57    }
58
59    /// Gets the words for the binary
60    #[inline]
61    pub fn as_words(&self) -> &[u32] {
62        self.as_ref()
63    }
64}
65
66impl TryFrom<Vec<u8>> for Binary {
67    type Error = crate::Error;
68
69    #[inline]
70    fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
71        if v.len() % size_of::<u32>() != 0 {
72            Err(crate::Error {
73                inner: spirv_tools_sys::shared::SpirvResult::InvalidBinary,
74                diagnostic: None,
75            })
76        } else {
77            Ok(Binary::OwnedU8(v))
78        }
79    }
80}
81
82impl AsRef<[u32]> for Binary {
83    #[inline]
84    fn as_ref(&self) -> &[u32] {
85        match self {
86            #[cfg(feature = "use-compiled-tools")]
87            Self::External(bin) => bin.as_ref(),
88            Self::OwnedU32(v) => v,
89            Self::OwnedU8(v) => {
90                // If you hit a panic here it's because try_from wasn't used ;)
91                to_binary(v).unwrap()
92            }
93        }
94    }
95}
96
97impl AsRef<[u8]> for Binary {
98    #[inline]
99    fn as_ref(&self) -> &[u8] {
100        match self {
101            #[cfg(feature = "use-compiled-tools")]
102            Self::External(bin) => bin.as_ref(),
103            Self::OwnedU32(v) => from_binary(v),
104            Self::OwnedU8(v) => v,
105        }
106    }
107}
108
109use std::fmt;
110
111impl fmt::Debug for Binary {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        let mut ds = match self {
114            #[cfg(feature = "use-compiled-tools")]
115            Self::External(_) => f.debug_struct("External"),
116            Self::OwnedU32(_) => f.debug_struct("OwnedU32"),
117            Self::OwnedU8(_) => f.debug_struct("OwnedU8"),
118        };
119
120        ds.field("word_count", &self.as_words().len()).finish()
121    }
122}
123
124/// Transmutes a SPIRV binary, which are stored as 32 bit words, into a more
125/// digestible byte array
126#[inline]
127pub fn from_binary(bin: &[u32]) -> &[u8] {
128    unsafe { std::slice::from_raw_parts(bin.as_ptr().cast(), size_of_val(bin)) }
129}
130
131/// Transmutes a regular byte array into a SPIRV binary of 32 bit words.
132/// Fails if the input is not `input.as_ptr() % 4` and `input.len() % 4`.
133#[inline]
134pub fn to_binary(bytes: &[u8]) -> Result<&[u32], crate::Error> {
135    if bytes.len() % size_of::<u32>() != 0 {
136        return Err(crate::Error {
137            inner: spirv_tools_sys::shared::SpirvResult::InvalidBinary,
138            diagnostic: None,
139        });
140    }
141    if bytes.as_ptr().addr() % size_of::<u32>() != 0 {
142        return Err(crate::Error {
143            inner: spirv_tools_sys::shared::SpirvResult::InvalidBinary,
144            diagnostic: None,
145        });
146    }
147
148    #[allow(clippy::size_of_in_element_count)]
149    Ok(
150        unsafe {
151            std::slice::from_raw_parts(bytes.as_ptr().cast(), bytes.len() / size_of::<u32>())
152        },
153    )
154}