spirv_tools/assembler/
compiled.rs

1use spirv_tools_sys::{assembler, shared};
2
3pub struct CompiledAssembler {
4    inner: *mut shared::ToolContext,
5}
6
7use super::Assembler;
8
9impl Assembler for CompiledAssembler {
10    fn with_env(target_env: crate::TargetEnv) -> Self {
11        Self {
12            inner: unsafe { shared::context_create(target_env) },
13        }
14    }
15
16    fn assemble(
17        &self,
18        text: &str,
19        options: super::AssemblerOptions,
20    ) -> Result<crate::binary::Binary, crate::error::Error> {
21        unsafe {
22            let mut binary = std::ptr::null_mut();
23            let mut diagnostic = std::ptr::null_mut();
24
25            let res = assembler::assemble(
26                self.inner,
27                text.as_ptr().cast(),
28                text.len(),
29                options.into(),
30                &mut binary,
31                &mut diagnostic,
32            );
33
34            // Always wrap diagnostic, it's fine if it's null
35            let diagnostic = crate::error::Diagnostic::from_diag(diagnostic).ok();
36
37            match res {
38                shared::SpirvResult::Success => {
39                    if binary.is_null() {
40                        return Err(crate::error::Error {
41                            inner: shared::SpirvResult::InternalError,
42                            diagnostic: Some("spirv assemble indicated success but did not return a valid binary".to_owned().into()),
43                        });
44                    }
45
46                    let bin = crate::binary::external::ExternalBinary::new(binary);
47                    Ok(crate::binary::Binary::External(bin))
48                }
49                other => Err(crate::error::Error {
50                    inner: other,
51                    diagnostic,
52                }),
53            }
54        }
55    }
56
57    fn disassemble(
58        &self,
59        binary: impl AsRef<[u32]>,
60        options: super::DisassembleOptions,
61    ) -> Result<Option<String>, crate::error::Error> {
62        unsafe {
63            let mut text = std::ptr::null_mut();
64            let mut diagnostic = std::ptr::null_mut();
65
66            let binary = binary.as_ref();
67
68            let res = assembler::disassemble(
69                self.inner,
70                binary.as_ptr().cast(),
71                binary.len(),
72                options.into(),
73                &mut text,
74                &mut diagnostic,
75            );
76
77            // Always wrap diagnostic, it's fine if it's null
78            let diagnostic = crate::error::Diagnostic::from_diag(diagnostic).ok();
79
80            match res {
81                shared::SpirvResult::Success => {
82                    if text.is_null() {
83                        return Ok(None);
84                    }
85
86                    // Sanity check the text first
87                    let disassemble_res = std::str::from_utf8(std::slice::from_raw_parts(
88                        (*text).data.cast::<u8>(),
89                        (*text).length,
90                    ))
91                    .map(|disasm| Some(disasm.to_owned()))
92                    .map_err(|e| crate::error::Error {
93                        inner: shared::SpirvResult::InvalidText,
94                        diagnostic: Some(
95                            format!("spirv disassemble returned non-utf8 text: {}", e).into(),
96                        ),
97                    });
98
99                    assembler::text_destroy(text);
100
101                    disassemble_res
102                }
103                other => Err(crate::error::Error {
104                    inner: other,
105                    diagnostic,
106                }),
107            }
108        }
109    }
110}
111
112impl Default for CompiledAssembler {
113    fn default() -> Self {
114        Self::with_env(crate::TargetEnv::default())
115    }
116}
117
118impl Drop for CompiledAssembler {
119    fn drop(&mut self) {
120        unsafe {
121            shared::context_destroy(self.inner);
122        }
123    }
124}