1use alloc::{vec, vec::Vec};
2
3use spirv::Word;
4
5use crate::{Handle, UniqueArena};
6
7pub(super) fn bytes_to_words(bytes: &[u8]) -> Vec<Word> {
8 bytes
9 .chunks(4)
10 .map(|chars| chars.iter().rev().fold(0u32, |u, c| (u << 8) | *c as u32))
11 .collect()
12}
13
14pub(super) fn string_to_words(input: &str) -> Vec<Word> {
15 let bytes = input.as_bytes();
16
17 str_bytes_to_words(bytes)
18}
19
20pub(super) fn str_bytes_to_words(bytes: &[u8]) -> Vec<Word> {
21 let mut words = bytes_to_words(bytes);
22 if bytes.len() % 4 == 0 {
23 words.push(0x0u32);
25 }
26
27 words
28}
29
30#[allow(unstable_name_collisions)]
32pub(super) fn string_to_byte_chunks(input: &str, limit: usize) -> Vec<&[u8]> {
33 let mut offset: usize = 0;
34 let mut start: usize = 0;
35 let mut words = vec![];
36 while offset < input.len() {
37 offset = input.floor_char_boundary(offset + limit);
38 words.push(input[start..offset].as_bytes());
39 start = offset;
40 }
41
42 words
43}
44
45pub(super) const fn map_storage_class(space: crate::AddressSpace) -> spirv::StorageClass {
46 match space {
47 crate::AddressSpace::Handle => spirv::StorageClass::UniformConstant,
48 crate::AddressSpace::Function => spirv::StorageClass::Function,
49 crate::AddressSpace::Private => spirv::StorageClass::Private,
50 crate::AddressSpace::Storage { .. } => spirv::StorageClass::StorageBuffer,
51 crate::AddressSpace::Uniform => spirv::StorageClass::Uniform,
52 crate::AddressSpace::WorkGroup => spirv::StorageClass::Workgroup,
53 crate::AddressSpace::PushConstant => spirv::StorageClass::PushConstant,
54 }
55}
56
57pub(super) fn contains_builtin(
58 binding: Option<&crate::Binding>,
59 ty: Handle<crate::Type>,
60 arena: &UniqueArena<crate::Type>,
61 built_in: crate::BuiltIn,
62) -> bool {
63 if let Some(&crate::Binding::BuiltIn(bi)) = binding {
64 bi == built_in
65 } else if let crate::TypeInner::Struct { ref members, .. } = arena[ty].inner {
66 members
67 .iter()
68 .any(|member| contains_builtin(member.binding.as_ref(), member.ty, arena, built_in))
69 } else {
70 false }
72}
73
74impl crate::AddressSpace {
75 pub(super) const fn to_spirv_semantics_and_scope(
76 self,
77 ) -> (spirv::MemorySemantics, spirv::Scope) {
78 match self {
79 Self::Storage { .. } => (spirv::MemorySemantics::UNIFORM_MEMORY, spirv::Scope::Device),
80 Self::WorkGroup => (
81 spirv::MemorySemantics::WORKGROUP_MEMORY,
82 spirv::Scope::Workgroup,
83 ),
84 _ => (spirv::MemorySemantics::empty(), spirv::Scope::Invocation),
85 }
86 }
87}
88
89pub fn global_needs_wrapper(ir_module: &crate::Module, var: &crate::GlobalVariable) -> bool {
95 match var.space {
96 crate::AddressSpace::Uniform
97 | crate::AddressSpace::Storage { .. }
98 | crate::AddressSpace::PushConstant => {}
99 _ => return false,
100 };
101 match ir_module.types[var.ty].inner {
102 crate::TypeInner::Struct {
103 ref members,
104 span: _,
105 } => match members.last() {
106 Some(member) => match ir_module.types[member.ty].inner {
107 crate::TypeInner::Array {
109 size: crate::ArraySize::Dynamic,
110 ..
111 } => false,
112 _ => true,
113 },
114 None => false,
115 },
116 crate::TypeInner::BindingArray { .. } => false,
117 _ => true,
119 }
120}
121
122trait U8Internal {
124 fn is_utf8_char_boundary(&self) -> bool;
125}
126
127impl U8Internal for u8 {
128 fn is_utf8_char_boundary(&self) -> bool {
129 (*self as i8) >= -0x40
131 }
132}
133
134trait StrUnstable {
135 fn floor_char_boundary(&self, index: usize) -> usize;
136}
137
138impl StrUnstable for str {
139 fn floor_char_boundary(&self, index: usize) -> usize {
140 if index >= self.len() {
141 self.len()
142 } else {
143 let lower_bound = index.saturating_sub(3);
144 let new_index = self.as_bytes()[lower_bound..=index]
145 .iter()
146 .rposition(|b| b.is_utf8_char_boundary());
147
148 unsafe { lower_bound + new_index.unwrap_unchecked() }
150 }
151 }
152}