1use std::str::FromStr;
4
5use crate::{Error, Instance, inst::*, syntax::*};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct StructMemberType {
9 pub name: String,
10 pub ty: Type,
11 pub size: Option<u32>,
12 pub align: Option<u32>,
13}
14
15impl StructMemberType {
16 pub fn new(name: String, ty: Type) -> Self {
17 Self {
18 name,
19 ty,
20 size: None,
21 align: None,
22 }
23 }
24}
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct StructType {
28 pub name: String,
29 pub members: Vec<StructMemberType>,
30}
31
32impl From<StructType> for Type {
33 fn from(value: StructType) -> Self {
34 Self::Struct(Box::new(value))
35 }
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39pub enum TextureType {
40 Sampled1D(SampledType),
42 Sampled2D(SampledType),
43 Sampled2DArray(SampledType),
44 Sampled3D(SampledType),
45 SampledCube(SampledType),
46 SampledCubeArray(SampledType),
47 Multisampled2D(SampledType),
49 DepthMultisampled2D,
50 External,
52 Storage1D(TexelFormat, AccessMode),
54 Storage2D(TexelFormat, AccessMode),
55 Storage2DArray(TexelFormat, AccessMode),
56 Storage3D(TexelFormat, AccessMode),
57 Depth2D,
59 Depth2DArray,
60 DepthCube,
61 DepthCubeArray,
62 #[cfg(feature = "naga-ext")]
63 Sampled1DArray(SampledType),
64 #[cfg(feature = "naga-ext")]
65 Storage1DArray(TexelFormat, AccessMode),
66 #[cfg(feature = "naga-ext")]
67 Multisampled2DArray(SampledType),
68}
69
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub enum TextureDimensions {
72 D1,
73 D2,
74 D3,
75}
76
77impl TextureType {
78 pub fn dimensions(&self) -> TextureDimensions {
79 match self {
80 Self::Sampled1D(_) | Self::Storage1D(_, _) => TextureDimensions::D1,
81 Self::Sampled2D(_)
82 | Self::Sampled2DArray(_)
83 | Self::SampledCube(_)
84 | Self::SampledCubeArray(_)
85 | Self::Multisampled2D(_)
86 | Self::Depth2D
87 | Self::Depth2DArray
88 | Self::DepthCube
89 | Self::DepthCubeArray
90 | Self::DepthMultisampled2D
91 | Self::Storage2D(_, _)
92 | Self::Storage2DArray(_, _)
93 | Self::External => TextureDimensions::D2,
94 Self::Sampled3D(_) | Self::Storage3D(_, _) => TextureDimensions::D3,
95 #[cfg(feature = "naga-ext")]
96 Self::Sampled1DArray(_) | Self::Storage1DArray(_, _) => TextureDimensions::D1,
97 #[cfg(feature = "naga-ext")]
98 Self::Multisampled2DArray(_) => TextureDimensions::D2,
99 }
100 }
101 pub fn sampled_type(&self) -> Option<SampledType> {
102 match self {
103 TextureType::Sampled1D(st) => Some(*st),
104 TextureType::Sampled2D(st) => Some(*st),
105 TextureType::Sampled2DArray(st) => Some(*st),
106 TextureType::Sampled3D(st) => Some(*st),
107 TextureType::SampledCube(st) => Some(*st),
108 TextureType::SampledCubeArray(st) => Some(*st),
109 TextureType::Multisampled2D(st) => Some(*st),
110 TextureType::DepthMultisampled2D => None,
111 TextureType::External => None,
112 TextureType::Storage1D(_, _) => None,
113 TextureType::Storage2D(_, _) => None,
114 TextureType::Storage2DArray(_, _) => None,
115 TextureType::Storage3D(_, _) => None,
116 TextureType::Depth2D => None,
117 TextureType::Depth2DArray => None,
118 TextureType::DepthCube => None,
119 TextureType::DepthCubeArray => None,
120 #[cfg(feature = "naga-ext")]
121 TextureType::Sampled1DArray(st) => Some(*st),
122 #[cfg(feature = "naga-ext")]
123 TextureType::Storage1DArray(_, _) => None,
124 #[cfg(feature = "naga-ext")]
125 TextureType::Multisampled2DArray(st) => Some(*st),
126 }
127 }
128 pub fn channel_type(&self) -> SampledType {
129 match self {
130 TextureType::Sampled1D(st) => *st,
131 TextureType::Sampled2D(st) => *st,
132 TextureType::Sampled2DArray(st) => *st,
133 TextureType::Sampled3D(st) => *st,
134 TextureType::SampledCube(st) => *st,
135 TextureType::SampledCubeArray(st) => *st,
136 TextureType::Multisampled2D(st) => *st,
137 TextureType::DepthMultisampled2D => SampledType::F32,
138 TextureType::External => SampledType::F32,
139 TextureType::Storage1D(f, _) => f.channel_type(),
140 TextureType::Storage2D(f, _) => f.channel_type(),
141 TextureType::Storage2DArray(f, _) => f.channel_type(),
142 TextureType::Storage3D(f, _) => f.channel_type(),
143 TextureType::Depth2D => SampledType::F32,
144 TextureType::Depth2DArray => SampledType::F32,
145 TextureType::DepthCube => SampledType::F32,
146 TextureType::DepthCubeArray => SampledType::F32,
147 #[cfg(feature = "naga-ext")]
148 TextureType::Sampled1DArray(st) => *st,
149 #[cfg(feature = "naga-ext")]
150 TextureType::Storage1DArray(f, _) => f.channel_type(),
151 #[cfg(feature = "naga-ext")]
152 TextureType::Multisampled2DArray(st) => *st,
153 }
154 }
155 pub fn is_depth(&self) -> bool {
157 matches!(
158 self,
159 TextureType::Depth2D
160 | TextureType::Depth2DArray
161 | TextureType::DepthCube
162 | TextureType::DepthCubeArray
163 )
164 }
165 pub fn is_storage(&self) -> bool {
166 match self {
167 TextureType::Storage1D(_, _)
168 | TextureType::Storage2D(_, _)
169 | TextureType::Storage2DArray(_, _)
170 | TextureType::Storage3D(_, _) => true,
171 #[cfg(feature = "naga-ext")]
172 TextureType::Storage1DArray(_, _) => true,
173 _ => false,
174 }
175 }
176 pub fn is_sampled(&self) -> bool {
177 match self {
178 TextureType::Sampled1D(_)
179 | TextureType::Sampled2D(_)
180 | TextureType::Sampled2DArray(_)
181 | TextureType::Sampled3D(_)
182 | TextureType::SampledCube(_)
183 | TextureType::SampledCubeArray(_) => true,
184 #[cfg(feature = "naga-ext")]
185 TextureType::Sampled1DArray(_) => true,
186 _ => false,
187 }
188 }
189 pub fn is_arrayed(&self) -> bool {
190 match self {
191 TextureType::Sampled2DArray(_)
192 | TextureType::SampledCubeArray(_)
193 | TextureType::Storage2DArray(_, _)
194 | TextureType::Depth2DArray
195 | TextureType::DepthCubeArray => true,
196 #[cfg(feature = "naga-ext")]
197 TextureType::Sampled1DArray(_)
198 | TextureType::Storage1DArray(_, _)
199 | TextureType::Multisampled2DArray(_) => true,
200 _ => false,
201 }
202 }
203 pub fn is_multisampled(&self) -> bool {
204 match self {
205 TextureType::Multisampled2D(_) | TextureType::DepthMultisampled2D => true,
206 #[cfg(feature = "naga-ext")]
207 TextureType::Multisampled2DArray(_) => true,
208 _ => false,
209 }
210 }
211 pub fn is_cube(&self) -> bool {
212 matches!(
213 self,
214 TextureType::SampledCube(_)
215 | TextureType::SampledCubeArray(_)
216 | TextureType::DepthCube
217 | TextureType::DepthCubeArray
218 )
219 }
220}
221
222impl TryFrom<&Type> for SampledType {
223 type Error = Error;
224
225 fn try_from(value: &Type) -> Result<Self, Self::Error> {
226 match value {
227 Type::I32 => Ok(SampledType::I32),
228 Type::U32 => Ok(SampledType::U32),
229 Type::F32 => Ok(SampledType::F32),
230 _ => Err(Error::SampledType(value.clone())),
231 }
232 }
233}
234
235impl From<SampledType> for Type {
236 fn from(value: SampledType) -> Self {
237 match value {
238 SampledType::I32 => Type::I32,
239 SampledType::U32 => Type::U32,
240 SampledType::F32 => Type::F32,
241 }
242 }
243}
244
245#[derive(Clone, Debug, PartialEq, Eq, Hash)]
246pub enum SamplerType {
247 Sampler,
248 SamplerComparison,
249}
250
251impl FromStr for SamplerType {
252 type Err = ();
253
254 fn from_str(s: &str) -> Result<Self, Self::Err> {
255 match s {
256 "sampler" => Ok(Self::Sampler),
257 "sampler_comparison" => Ok(Self::SamplerComparison),
258 _ => Err(()),
259 }
260 }
261}
262
263#[derive(Clone, Debug, PartialEq, Eq)]
265pub enum Type {
266 Bool,
267 AbstractInt,
268 AbstractFloat,
269 I32,
270 U32,
271 F32,
272 F16,
273 Struct(Box<StructType>),
274 Array(Box<Type>, Option<usize>),
275 Vec(u8, Box<Type>),
276 Mat(u8, u8, Box<Type>),
277 Atomic(Box<Type>),
278 Ptr(AddressSpace, Box<Type>, AccessMode),
279 Ref(AddressSpace, Box<Type>, AccessMode),
280 Texture(TextureType),
281 Sampler(SamplerType),
282 Unknown,
285 #[cfg(feature = "naga-ext")]
286 I64,
287 #[cfg(feature = "naga-ext")]
288 U64,
289 #[cfg(feature = "naga-ext")]
290 F64,
291 #[cfg(feature = "naga-ext")]
292 BindingArray(Box<Type>, Option<usize>),
293 #[cfg(feature = "naga-ext")]
294 RayQuery(Option<AccelerationStructureFlags>),
295 #[cfg(feature = "naga-ext")]
296 AccelerationStructure(Option<AccelerationStructureFlags>),
297}
298
299impl Type {
300 pub fn is_scalar(&self) -> bool {
302 match self {
303 Type::Bool
304 | Type::AbstractInt
305 | Type::AbstractFloat
306 | Type::I32
307 | Type::U32
308 | Type::F32
309 | Type::F16 => true,
310 #[cfg(feature = "naga-ext")]
311 Type::I64 | Type::U64 | Type::F64 => true,
312 _ => false,
313 }
314 }
315
316 pub fn is_numeric(&self) -> bool {
318 match self {
319 Type::AbstractInt
320 | Type::AbstractFloat
321 | Type::I32
322 | Type::U32
323 | Type::F32
324 | Type::F16 => true,
325 #[cfg(feature = "naga-ext")]
326 Type::I64 | Type::U64 | Type::F64 => true,
327 _ => false,
328 }
329 }
330
331 pub fn is_integer(&self) -> bool {
333 match self {
334 Type::AbstractInt | Type::I32 | Type::U32 => true,
335 #[cfg(feature = "naga-ext")]
336 Type::I64 | Type::U64 => true,
337 _ => false,
338 }
339 }
340
341 pub fn is_signed(&self) -> bool {
343 match self {
344 Type::AbstractInt | Type::AbstractFloat | Type::I32 | Type::F32 | Type::F16 => true,
345 #[cfg(feature = "naga-ext")]
346 Type::I64 | Type::F64 => true,
347 _ => false,
348 }
349 }
350
351 pub fn is_float(&self) -> bool {
353 match self {
354 Type::AbstractFloat | Type::F32 | Type::F16 => true,
355 #[cfg(feature = "naga-ext")]
356 Type::F64 => true,
357 _ => false,
358 }
359 }
360
361 pub fn is_abstract(&self) -> bool {
363 match self {
364 Type::AbstractInt => true,
365 Type::AbstractFloat => true,
366 Type::Array(ty, _) | Type::Vec(_, ty) | Type::Mat(_, _, ty) => ty.is_abstract(),
367 _ => false,
368 }
369 }
370
371 pub fn is_concrete(&self) -> bool {
372 match self {
373 Type::Unknown => false,
374 _ => !self.is_abstract(),
375 }
376 }
377
378 pub fn is_storable(&self) -> bool {
380 self.is_concrete()
381 && match self {
382 Type::Bool
383 | Type::I32
384 | Type::U32
385 | Type::F32
386 | Type::F16
387 | Type::Struct(_)
388 | Type::Array(_, _)
389 | Type::Vec(_, _)
390 | Type::Mat(_, _, _)
391 | Type::Atomic(_) => true,
392 #[cfg(feature = "naga-ext")]
393 Type::I64 | Type::U64 | Type::F64 => true,
394 _ => false,
395 }
396 }
397
398 pub fn is_array(&self) -> bool {
399 matches!(self, Type::Array(_, _))
400 }
401 pub fn is_vec(&self) -> bool {
402 matches!(self, Type::Vec(_, _))
403 }
404 pub fn is_i32(&self) -> bool {
405 matches!(self, Type::I32)
406 }
407 pub fn is_u32(&self) -> bool {
408 matches!(self, Type::U32)
409 }
410 pub fn is_f32(&self) -> bool {
411 matches!(self, Type::F32)
412 }
413 #[cfg(feature = "naga-ext")]
414 pub fn is_i64(&self) -> bool {
415 matches!(self, Type::I64)
416 }
417 #[cfg(feature = "naga-ext")]
418 pub fn is_u64(&self) -> bool {
419 matches!(self, Type::U64)
420 }
421 #[cfg(feature = "naga-ext")]
422 pub fn is_f64(&self) -> bool {
423 matches!(self, Type::F64)
424 }
425 pub fn is_bool(&self) -> bool {
426 matches!(self, Type::Bool)
427 }
428 pub fn is_mat(&self) -> bool {
429 matches!(self, Type::Mat(_, _, _))
430 }
431 pub fn is_abstract_int(&self) -> bool {
432 matches!(self, Type::AbstractInt)
433 }
434
435 pub fn unwrap_atomic(self) -> Box<Type> {
436 match self {
437 Type::Atomic(ty) => ty,
438 val => panic!("called `Type::unwrap_atomic()` on a `{val}` value"),
439 }
440 }
441
442 pub fn unwrap_struct(self) -> Box<StructType> {
443 match self {
444 Type::Struct(ty) => ty,
445 val => panic!("called `Type::unwrap_struct()` on a `{val}` value"),
446 }
447 }
448
449 pub fn unwrap_vec(self) -> (u8, Box<Type>) {
450 match self {
451 Type::Vec(size, ty) => (size, ty),
452 val => panic!("called `Type::unwrap_vec()` on a `{val}` value"),
453 }
454 }
455}
456
457pub trait Ty {
458 fn ty(&self) -> Type;
460
461 fn inner_ty(&self) -> Type {
465 self.ty()
466 }
467}
468
469impl Ty for Type {
470 fn ty(&self) -> Type {
471 self.clone()
472 }
473
474 fn inner_ty(&self) -> Type {
475 match self {
476 Type::Bool => self.clone(),
477 Type::AbstractInt => self.clone(),
478 Type::AbstractFloat => self.clone(),
479 Type::I32 => self.clone(),
480 Type::U32 => self.clone(),
481 Type::F32 => self.clone(),
482 Type::F16 => self.clone(),
483 Type::Struct(_) => self.clone(),
484 Type::Array(ty, _) => ty.ty(),
485 Type::Vec(_, ty) => ty.ty(),
486 Type::Mat(_, _, ty) => ty.ty(),
487 Type::Atomic(ty) => ty.ty(),
488 Type::Ptr(_, ty, _) => ty.ty(),
489 Type::Ref(_, ty, _) => ty.ty(),
490 Type::Texture(_) => self.clone(),
491 Type::Sampler(_) => self.clone(),
492 Type::Unknown => self.clone(),
493 #[cfg(feature = "naga-ext")]
494 Type::I64 => self.clone(),
495 #[cfg(feature = "naga-ext")]
496 Type::U64 => self.clone(),
497 #[cfg(feature = "naga-ext")]
498 Type::F64 => self.clone(),
499 #[cfg(feature = "naga-ext")]
500 Type::BindingArray(ty, _) => ty.ty(),
501 #[cfg(feature = "naga-ext")]
502 Type::RayQuery(_) => self.clone(),
503 #[cfg(feature = "naga-ext")]
504 Type::AccelerationStructure(_) => self.clone(),
505 }
506 }
507}
508
509impl Ty for Instance {
510 fn ty(&self) -> Type {
511 match self {
512 Instance::Literal(l) => l.ty(),
513 Instance::Struct(s) => s.ty(),
514 Instance::Array(a) => a.ty(),
515 Instance::Vec(v) => v.ty(),
516 Instance::Mat(m) => m.ty(),
517 Instance::Ptr(p) => p.ty(),
518 Instance::Ref(r) => r.ty(),
519 Instance::Atomic(a) => a.ty(),
520 Instance::Deferred(t) => t.ty(),
521 }
522 }
523 fn inner_ty(&self) -> Type {
524 match self {
525 Instance::Literal(l) => l.inner_ty(),
526 Instance::Struct(s) => s.inner_ty(),
527 Instance::Array(a) => a.inner_ty(),
528 Instance::Vec(v) => v.inner_ty(),
529 Instance::Mat(m) => m.inner_ty(),
530 Instance::Ptr(p) => p.inner_ty(),
531 Instance::Ref(r) => r.inner_ty(),
532 Instance::Atomic(a) => a.inner_ty(),
533 Instance::Deferred(t) => t.inner_ty(),
534 }
535 }
536}
537
538impl Ty for LiteralInstance {
539 fn ty(&self) -> Type {
540 match self {
541 LiteralInstance::Bool(_) => Type::Bool,
542 LiteralInstance::AbstractInt(_) => Type::AbstractInt,
543 LiteralInstance::AbstractFloat(_) => Type::AbstractFloat,
544 LiteralInstance::I32(_) => Type::I32,
545 LiteralInstance::U32(_) => Type::U32,
546 LiteralInstance::F32(_) => Type::F32,
547 LiteralInstance::F16(_) => Type::F16,
548 #[cfg(feature = "naga-ext")]
549 LiteralInstance::I64(_) => Type::I64,
550 #[cfg(feature = "naga-ext")]
551 LiteralInstance::U64(_) => Type::U64,
552 #[cfg(feature = "naga-ext")]
553 LiteralInstance::F64(_) => Type::F64,
554 }
555 }
556}
557
558impl Ty for StructInstance {
559 fn ty(&self) -> Type {
560 self.ty.clone().into()
561 }
562}
563
564impl Ty for ArrayInstance {
565 fn ty(&self) -> Type {
566 Type::Array(
567 Box::new(self.inner_ty().clone()),
568 (!self.runtime_sized).then_some(self.n()),
569 )
570 }
571 fn inner_ty(&self) -> Type {
572 self.get(0).unwrap().ty()
573 }
574}
575
576impl Ty for VecInstance {
577 fn ty(&self) -> Type {
578 Type::Vec(self.n() as u8, Box::new(self.inner_ty()))
579 }
580 fn inner_ty(&self) -> Type {
581 self.get(0).unwrap().ty()
582 }
583}
584
585impl Ty for MatInstance {
586 fn ty(&self) -> Type {
587 Type::Mat(self.c() as u8, self.r() as u8, Box::new(self.inner_ty()))
588 }
589 fn inner_ty(&self) -> Type {
590 self.get(0, 0).unwrap().ty()
591 }
592}
593
594impl Ty for PtrInstance {
595 fn ty(&self) -> Type {
596 Type::Ptr(
597 self.ptr.space,
598 Box::new(self.ptr.ty.clone()),
599 self.ptr.access,
600 )
601 }
602}
603
604impl Ty for RefInstance {
605 fn ty(&self) -> Type {
606 Type::Ref(self.space, Box::new(self.ty.clone()), self.access)
607 }
608}
609
610impl Ty for AtomicInstance {
611 fn ty(&self) -> Type {
612 Type::Atomic(self.inner_ty().into())
613 }
614 fn inner_ty(&self) -> Type {
615 self.inner().ty()
616 }
617}