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
use crate::error;
use crate::handle::{Handle, Id};
use crate::Compiler;

use crate::string::CompilerStr;
use spirv_cross_sys as sys;
use spirv_cross_sys::{SpvId, TypeId, VariableId};

impl<T> Compiler<T> {
    /// Gets the identifier (`OpName`) of an ID.
    pub fn name<I: Id>(&self, handle: Handle<I>) -> error::Result<Option<CompilerStr>> {
        let id = self.yield_id(handle)?;
        unsafe {
            let name = sys::spvc_compiler_get_name(self.ptr.as_ptr(), SpvId(id.id()));
            let name = CompilerStr::from_ptr(name, self.ctx.drop_guard());
            if name.is_empty() {
                Ok(None)
            } else {
                Ok(Some(name))
            }
        }
    }

    /// Overrides the identifier OpName of an ID.
    ///
    /// Identifiers beginning with underscores or identifiers which contain double underscores
    /// are reserved by the implementation.
    pub fn set_name<'str, I: Id>(
        &mut self,
        handle: Handle<I>,
        string: impl Into<CompilerStr<'str>>,
    ) -> error::Result<()> {
        let id = self.yield_id(handle)?;
        let string = string.into();

        unsafe {
            let cstring = string.into_cstring_ptr()?;

            sys::spvc_compiler_set_name(self.ptr.as_ptr(), SpvId(id.id()), cstring.as_ptr());

            // Sanity drop to show that the lifetime of the cstring is only up until
            // we have returned. AFAIK, SPIRV-Cross will do a string copy.
            // If it does not, then we'll have to keep this string alive for a while.
            drop(cstring);
            Ok(())
        }
    }

    /// Given a struct type ID, obtain the identifier for member number "index".
    pub fn member_name(
        &self,
        struct_type: Handle<TypeId>,
        index: u32,
    ) -> error::Result<Option<CompilerStr>> {
        let struct_type_id = self.yield_id(struct_type)?;
        let index = index;

        unsafe {
            let name = sys::spvc_compiler_get_member_name(self.ptr.as_ptr(), struct_type_id, index);
            let name = CompilerStr::from_ptr(name, self.ctx.drop_guard());
            if name.is_empty() {
                Ok(None)
            } else {
                Ok(Some(name))
            }
        }
    }

    /// Sets the member identifier for the given struct member.
    pub fn set_member_name<'str>(
        &mut self,
        struct_type: Handle<TypeId>,
        index: u32,
        string: impl Into<CompilerStr<'str>>,
    ) -> error::Result<()> {
        let struct_type_id = self.yield_id(struct_type)?;
        let index = index;
        let string = string.into();

        unsafe {
            let cstring = string.into_cstring_ptr()?;

            sys::spvc_compiler_set_member_name(
                self.ptr.as_ptr(),
                struct_type_id,
                index,
                cstring.as_ptr(),
            );

            // Sanity drop to show that the lifetime of the cstring is only up until
            // we have returned. AFAIK, SPIRV-Cross will do a string copy.
            // If it does not, then we'll have to keep this string alive for a while.
            drop(cstring);
            Ok(())
        }
    }
}

impl<T> Compiler<T> {
    /// When declaring buffer blocks in GLSL, the name declared in the GLSL source
    /// might not be the same as the name declared in the SPIR-V module due to naming conflicts.
    /// In this case, SPIRV-Cross needs to find a fallback-name, and it might only
    /// be possible to know this name after compiling to GLSL.
    ///
    /// This is particularly important for HLSL input and UAVs which tends to reuse the same block type
    /// for multiple distinct blocks. For these cases it is not possible to modify the name of the type itself
    /// because it might be unique. Instead, you can use this interface to check after compilation which
    /// name was actually used if your input SPIR-V tends to have this problem.
    ///
    /// For other names like remapped names for variables, etc., it's generally enough to query the name of the variables
    /// after compiling, block names are an exception to this rule.
    /// `handle` should be a handle to a variable with a Block-like type.
    ///
    /// This also applies to HLSL cbuffers.
    pub fn remapped_declared_block_name(
        &self,
        handle: impl Into<Handle<VariableId>>,
    ) -> error::Result<Option<CompilerStr<'static>>> {
        let handle = handle.into();
        let handle = self.yield_id(handle)?;
        unsafe {
            let name =
                sys::spvc_compiler_get_remapped_declared_block_name(self.ptr.as_ptr(), handle);

            // SAFETY: 'ctx is sound here
            // https://github.com/KhronosGroup/SPIRV-Cross/blob/main/spirv_cross_c.cpp#L2773
            let name = CompilerStr::from_ptr(name, self.ctx.drop_guard());
            if name.is_empty() {
                Ok(None)
            } else {
                Ok(Some(name))
            }
        }
    }
}