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
use spirv_tools_sys::{assembler, shared};

pub struct CompiledAssembler {
    inner: *mut shared::ToolContext,
}

use super::Assembler;

impl Assembler for CompiledAssembler {
    fn with_env(target_env: crate::TargetEnv) -> Self {
        Self {
            inner: unsafe { shared::context_create(target_env) },
        }
    }

    fn assemble(
        &self,
        text: &str,
        options: super::AssemblerOptions,
    ) -> Result<crate::binary::Binary, crate::error::Error> {
        unsafe {
            let mut binary = std::ptr::null_mut();
            let mut diagnostic = std::ptr::null_mut();

            let res = assembler::assemble(
                self.inner,
                text.as_ptr() as *const _,
                text.len(),
                options.into(),
                &mut binary,
                &mut diagnostic,
            );

            // Always wrap diagnostic, it's fine if it's null
            use std::convert::TryFrom;
            let diagnostic = crate::error::Diagnostic::try_from(diagnostic).ok();

            match res {
                shared::SpirvResult::Success => {
                    if binary.is_null() {
                        return Err(crate::error::Error {
                            inner: shared::SpirvResult::InternalError,
                            diagnostic: Some("spirv assemble indicated success but did not return a valid binary".to_owned().into()),
                        });
                    }

                    let bin = crate::binary::external::ExternalBinary::new(binary);
                    Ok(crate::binary::Binary::External(bin))
                }
                other => Err(crate::error::Error {
                    inner: other,
                    diagnostic,
                }),
            }
        }
    }
}

impl Default for CompiledAssembler {
    fn default() -> Self {
        Self::with_env(crate::TargetEnv::default())
    }
}

impl Drop for CompiledAssembler {
    fn drop(&mut self) {
        unsafe {
            shared::context_destroy(self.inner);
        }
    }
}