1use super::{address_space_str, ToWgsl, TryToWgsl};
4use crate::common;
5use crate::proc::TypeResolution;
6use crate::{Handle, Scalar, TypeInner};
7
8use alloc::string::String;
9use core::fmt::Write;
10
11pub trait TypeContext {
26 fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type;
30
31 fn type_name(&self, handle: Handle<crate::Type>) -> &str;
34
35 fn write_override<W: Write>(
37 &self,
38 r#override: Handle<crate::Override>,
39 out: &mut W,
40 ) -> core::fmt::Result;
41
42 fn write_unnamed_struct<W: Write>(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result;
49
50 fn write_non_wgsl_inner<W: Write>(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result {
62 write!(out, "{{non-WGSL Naga type {inner:?}}}")
63 }
64
65 fn write_non_wgsl_scalar<W: Write>(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result {
77 match scalar.kind {
78 crate::ScalarKind::Sint
79 | crate::ScalarKind::Uint
80 | crate::ScalarKind::Float
81 | crate::ScalarKind::Bool => write!(out, "{{non-WGSL Naga scalar {scalar:?}}}"),
82
83 crate::ScalarKind::AbstractInt => out.write_str("{AbstractInt}"),
88 crate::ScalarKind::AbstractFloat => out.write_str("{AbstractFloat}"),
89 }
90 }
91
92 fn write_type<W: Write>(&self, handle: Handle<crate::Type>, out: &mut W) -> core::fmt::Result {
97 let ty = self.lookup_type(handle);
98 match ty.inner {
99 TypeInner::Struct { .. } => out.write_str(self.type_name(handle))?,
100 ref other => self.write_type_inner(other, out)?,
101 }
102
103 Ok(())
104 }
105
106 fn write_type_inner<W: Write>(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result {
117 match try_write_type_inner(self, inner, out) {
118 Ok(()) => Ok(()),
119 Err(WriteTypeError::Format(err)) => Err(err),
120 Err(WriteTypeError::NonWgsl) => self.write_non_wgsl_inner(inner, out),
121 }
122 }
123
124 fn write_scalar<W: Write>(&self, scalar: Scalar, out: &mut W) -> core::fmt::Result {
126 match scalar.try_to_wgsl() {
127 Some(string) => out.write_str(string),
128 None => self.write_non_wgsl_scalar(scalar, out),
129 }
130 }
131
132 fn write_type_resolution<W: Write>(
134 &self,
135 resolution: &TypeResolution,
136 out: &mut W,
137 ) -> core::fmt::Result {
138 match *resolution {
139 TypeResolution::Handle(handle) => self.write_type(handle, out),
140 TypeResolution::Value(ref inner) => self.write_type_inner(inner, out),
141 }
142 }
143
144 fn write_type_conclusion<W: Write>(
145 &self,
146 conclusion: &crate::proc::Conclusion,
147 out: &mut W,
148 ) -> core::fmt::Result {
149 use crate::proc::Conclusion as Co;
150
151 match *conclusion {
152 Co::Value(ref inner) => self.write_type_inner(inner, out),
153 Co::Predeclared(ref predeclared) => out.write_str(&predeclared.struct_name()),
154 }
155 }
156
157 fn write_type_rule<W: Write>(
158 &self,
159 name: &str,
160 rule: &crate::proc::Rule,
161 out: &mut W,
162 ) -> core::fmt::Result {
163 write!(out, "fn {name}(")?;
164 for (i, arg) in rule.arguments.iter().enumerate() {
165 if i > 0 {
166 out.write_str(", ")?;
167 }
168 self.write_type_resolution(arg, out)?
169 }
170 out.write_str(") -> ")?;
171 self.write_type_conclusion(&rule.conclusion, out)?;
172 Ok(())
173 }
174
175 fn type_to_string(&self, handle: Handle<crate::Type>) -> String {
176 let mut buf = String::new();
177 self.write_type(handle, &mut buf).unwrap();
178 buf
179 }
180
181 fn type_resolution_to_string(&self, resolution: &TypeResolution) -> String {
182 let mut buf = String::new();
183 self.write_type_resolution(resolution, &mut buf).unwrap();
184 buf
185 }
186
187 fn type_rule_to_string(&self, name: &str, rule: &crate::proc::Rule) -> String {
188 let mut buf = String::new();
189 self.write_type_rule(name, rule, &mut buf).unwrap();
190 buf
191 }
192}
193
194fn try_write_type_inner<C, W>(ctx: &C, inner: &TypeInner, out: &mut W) -> Result<(), WriteTypeError>
195where
196 C: TypeContext + ?Sized,
197 W: Write,
198{
199 match *inner {
200 TypeInner::Vector { size, scalar } => {
201 write!(out, "vec{}<", common::vector_size_str(size))?;
202 ctx.write_scalar(scalar, out)?;
203 out.write_str(">")?;
204 }
205 TypeInner::Sampler { comparison: false } => {
206 write!(out, "sampler")?;
207 }
208 TypeInner::Sampler { comparison: true } => {
209 write!(out, "sampler_comparison")?;
210 }
211 TypeInner::Image {
212 dim,
213 arrayed,
214 class,
215 } => {
216 use crate::ImageClass as Ic;
218
219 let dim_str = dim.to_wgsl();
220 let arrayed_str = if arrayed { "_array" } else { "" };
221 match class {
222 Ic::Sampled { kind, multi } => {
223 let multisampled_str = if multi { "multisampled_" } else { "" };
224 write!(out, "texture_{multisampled_str}{dim_str}{arrayed_str}<")?;
225 ctx.write_scalar(Scalar { kind, width: 4 }, out)?;
226 out.write_str(">")?;
227 }
228 Ic::Depth { multi } => {
229 let multisampled_str = if multi { "multisampled_" } else { "" };
230 write!(
231 out,
232 "texture_depth_{multisampled_str}{dim_str}{arrayed_str}"
233 )?;
234 }
235 Ic::Storage { format, access } => {
236 let format_str = format.to_wgsl();
237 let access_str = if access.contains(crate::StorageAccess::ATOMIC) {
238 ",atomic"
239 } else if access
240 .contains(crate::StorageAccess::LOAD | crate::StorageAccess::STORE)
241 {
242 ",read_write"
243 } else if access.contains(crate::StorageAccess::LOAD) {
244 ",read"
245 } else {
246 ",write"
247 };
248 write!(
249 out,
250 "texture_storage_{dim_str}{arrayed_str}<{format_str}{access_str}>"
251 )?;
252 }
253 }
254 }
255 TypeInner::Scalar(scalar) => {
256 ctx.write_scalar(scalar, out)?;
257 }
258 TypeInner::Atomic(scalar) => {
259 out.write_str("atomic<")?;
260 ctx.write_scalar(scalar, out)?;
261 out.write_str(">")?;
262 }
263 TypeInner::Array {
264 base,
265 size,
266 stride: _,
267 } => {
268 write!(out, "array<")?;
272 match size {
273 crate::ArraySize::Constant(len) => {
274 ctx.write_type(base, out)?;
275 write!(out, ", {len}")?;
276 }
277 crate::ArraySize::Pending(r#override) => {
278 ctx.write_override(r#override, out)?;
279 }
280 crate::ArraySize::Dynamic => {
281 ctx.write_type(base, out)?;
282 }
283 }
284 write!(out, ">")?;
285 }
286 TypeInner::BindingArray { base, size } => {
287 write!(out, "binding_array<")?;
289 match size {
290 crate::ArraySize::Constant(len) => {
291 ctx.write_type(base, out)?;
292 write!(out, ", {len}")?;
293 }
294 crate::ArraySize::Pending(r#override) => {
295 ctx.write_override(r#override, out)?;
296 }
297 crate::ArraySize::Dynamic => {
298 ctx.write_type(base, out)?;
299 }
300 }
301 write!(out, ">")?;
302 }
303 TypeInner::Matrix {
304 columns,
305 rows,
306 scalar,
307 } => {
308 write!(
309 out,
310 "mat{}x{}<",
311 common::vector_size_str(columns),
312 common::vector_size_str(rows),
313 )?;
314 ctx.write_scalar(scalar, out)?;
315 out.write_str(">")?;
316 }
317 TypeInner::Pointer { base, space } => {
318 let (address, maybe_access) = address_space_str(space);
319 if let Some(space) = address {
323 write!(out, "ptr<{space}, ")?;
324 }
325 ctx.write_type(base, out)?;
326 if address.is_some() {
327 if let Some(access) = maybe_access {
328 write!(out, ", {access}")?;
329 }
330 write!(out, ">")?;
331 }
332 }
333 TypeInner::ValuePointer {
334 size: None,
335 scalar,
336 space,
337 } => {
338 let (address, maybe_access) = address_space_str(space);
339 if let Some(space) = address {
340 write!(out, "ptr<{space}, ")?;
341 ctx.write_scalar(scalar, out)?;
342 if let Some(access) = maybe_access {
343 write!(out, ", {access}")?;
344 }
345 write!(out, ">")?;
346 } else {
347 return Err(WriteTypeError::NonWgsl);
348 }
349 }
350 TypeInner::ValuePointer {
351 size: Some(size),
352 scalar,
353 space,
354 } => {
355 let (address, maybe_access) = address_space_str(space);
356 if let Some(space) = address {
357 write!(out, "ptr<{}, vec{}<", space, common::vector_size_str(size),)?;
358 ctx.write_scalar(scalar, out)?;
359 out.write_str(">")?;
360 if let Some(access) = maybe_access {
361 write!(out, ", {access}")?;
362 }
363 write!(out, ">")?;
364 } else {
365 return Err(WriteTypeError::NonWgsl);
366 }
367 write!(out, ">")?;
368 }
369 TypeInner::AccelerationStructure { vertex_return } => {
370 let caps = if vertex_return { "<vertex_return>" } else { "" };
371 write!(out, "acceleration_structure{caps}")?
372 }
373 TypeInner::Struct { .. } => {
374 ctx.write_unnamed_struct(inner, out)?;
375 }
376 TypeInner::RayQuery { vertex_return } => {
377 let caps = if vertex_return { "<vertex_return>" } else { "" };
378 write!(out, "ray_query{caps}")?
379 }
380 }
381
382 Ok(())
383}
384
385enum WriteTypeError {
389 Format(core::fmt::Error),
390 NonWgsl,
391}
392
393impl From<core::fmt::Error> for WriteTypeError {
394 fn from(err: core::fmt::Error) -> Self {
395 Self::Format(err)
396 }
397}
398
399impl TypeContext for crate::proc::GlobalCtx<'_> {
414 fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type {
415 &self.types[handle]
416 }
417
418 fn type_name(&self, handle: Handle<crate::Type>) -> &str {
419 self.types[handle]
420 .name
421 .as_deref()
422 .unwrap_or("{anonymous type}")
423 }
424
425 fn write_unnamed_struct<W: Write>(&self, _: &TypeInner, out: &mut W) -> core::fmt::Result {
426 write!(out, "{{unnamed struct}}")
427 }
428
429 fn write_override<W: Write>(
430 &self,
431 handle: Handle<crate::Override>,
432 out: &mut W,
433 ) -> core::fmt::Result {
434 match self.overrides[handle].name {
435 Some(ref name) => out.write_str(name),
436 None => write!(out, "{{anonymous override {handle:?}}}"),
437 }
438 }
439}
440
441impl TypeContext for crate::UniqueArena<crate::Type> {
453 fn lookup_type(&self, handle: Handle<crate::Type>) -> &crate::Type {
454 &self[handle]
455 }
456
457 fn type_name(&self, handle: Handle<crate::Type>) -> &str {
458 self[handle].name.as_deref().unwrap_or("{anonymous type}")
459 }
460
461 fn write_unnamed_struct<W: Write>(&self, inner: &TypeInner, out: &mut W) -> core::fmt::Result {
462 write!(out, "{{unnamed struct {inner:?}}}")
463 }
464
465 fn write_override<W: Write>(
466 &self,
467 handle: Handle<crate::Override>,
468 out: &mut W,
469 ) -> core::fmt::Result {
470 write!(out, "{{override {handle:?}}}")
471 }
472}