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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
//! Safe and rich Rust wrapper around the Vulkan API.
//!
//! # Starting off with Vulkano
//!
//! The steps for using Vulkan through Vulkano are in principle not any different from using
//! the raw Vulkan API, but the details may be different for the sake of idiomaticity, safety
//! and convenience.
//!
//! 1. Create a [`VulkanLibrary`]. This represents a Vulkan library on the system, which must be
//!    loaded before you can do anything with Vulkan.
//!
//! 2. Create an [`Instance`]. This is the API entry point, and represents an initialised Vulkan
//!    library.
//!
//! 3. If you intend to show graphics to the user on a window or a screen, create a [`Surface`].
//!    A `Surface` is created from a window identifier or handle, that is specific to the display or
//!    windowing system being used. The [`vulkano-win`] crate, which is part of the Vulkano
//!    project, can make this step easier.
//!
//! 4. [Enumerate the physical devices] that are available on the `Instance`, and choose one that
//!    is suitable for your program. A [`PhysicalDevice`] represents a Vulkan-capable device that
//!    is available on the system, such as a graphics card, a software implementation, etc.
//!
//! 6. Create a [`Device`] and accompanying [`Queue`]s from the selected `PhysicalDevice`.
//!    The `Device` is the most important object of Vulkan, and you need one to create almost
//!    every other object. `Queue`s are created together with the `Device`, and are used to submit
//!    work to the device to make it do something.
//!
//! 7. If you created a `Surface` earlier, create a [`Swapchain`]. This object contains special
//!    images that correspond to the contents of the surface. Whenever you want to
//!    change the contents (show something new to the user), you must first *acquire* one of these
//!    images from the swapchain, fill it with the new contents (by rendering, copying or any
//!    other means), and then *present* it back to the swapchain.
//!    A swapchain can become outdated if the properties of the surface change, such as when
//!    the size of the window changes. It then becomes necessary to create a new swapchain.
//!
//! 8. Record a [*command buffer*](crate::command_buffer), containing commands that the device must
//!    execute. Then build the command buffer and submit it to a `Queue`.
//!
//! Many different operations can be recorded to a command buffer, such as *draw*, *compute* and
//! *transfer* operations. To do any of these things, you will need to create several other objects,
//! depending on your specific needs. This includes:
//!
//! - [*Buffers*] store general-purpose data on memory accessible by the device. This can include
//!   mesh data (vertices, texture coordinates etc.), lighting information, matrices, and anything
//!   else you can think of.
//!
//! - [*Images*] store texel data, arranged in a grid of one or more dimensions. They can be used
//!   as textures, depth/stencil buffers, framebuffers and as part of a swapchain.
//!
//! - [*Pipelines*] describe operations on the device. They include one or more [*shader*]s, small
//!   programs that the device will execute as part of a pipeline.
//!   Pipelines come in several types:
//!   - A [`ComputePipeline`] describes how *dispatch* commands are to be performed.
//!   - A [`GraphicsPipeline`] describes how *draw* commands are to be performed.
//!
//! - [*Descriptor sets*] make buffers, images and other objects available to shaders. The
//!   arrangement of these resources in shaders is described by a [`DescriptorSetLayout`]. One or
//!   more of these layouts in turn forms a [`PipelineLayout`], which is used when creating a
//!   pipeline object.
//!
//! - For more complex, multi-stage draw operations, you can create a [`RenderPass`] object.
//!   This object describes the stages, known as subpasses, that draw operations consist of,
//!   how they interact with one another, and which types of images are available in each subpass.
//!   You must also create a [`Framebuffer`], which contains the image objects that are to be used
//!   in a render pass.
//!
//! # `_unchecked` functions
//!
//! Many functions in Vulkano have two versions: the normal function, which is usually safe to
//! call, and another function with `_unchecked` added onto the end of the name, which is unsafe
//! to call. The `_unchecked` functions skip all validation checks, so they are usually more
//! efficient, but you must ensure that you meet the validity/safety requirements of the function.
//!
//! For all `_unchecked` functions, a call to the function is valid, if a call to the
//! corresponding normal function with the same arguments would return without any error.
//! This includes following all the valid usage requirements of the Vulkan specification, but may
//! also include additional requirements specific to Vulkano.
//! **All other usage of `_unchecked` functions may be undefined behavior.**
//!
//! Because there are potentially many `_unchecked` functions, and because their name and operation
//! can be straightforwardly understood based on the corresponding normal function, they are hidden
//! from the Vulkano documentation by default. You can unhide them by enabling the
//! `document_unchecked` cargo feature, and then generating the documentation with the command
//! `cargo doc --open`.
//!
//! # Cargo features
//!
//! | Feature              | Description                                                    |
//! |----------------------|----------------------------------------------------------------|
//! | `macros`             | Include reexports from [`vulkano-macros`]. Enabled by default. |
//! | `document_unchecked` | Include `_unchecked` functions in the generated documentation. |
//! | `serde`              | Enables (de)serialization of certain types using [`serde`].    |
//!
//! [`VulkanLibrary`]: crate::VulkanLibrary
//! [`Instance`]: crate::instance::Instance
//! [`Surface`]: crate::swapchain::Surface
//! [`vulkano-win`]: https://crates.io/crates/vulkano-win
//! [Enumerate the physical devices]: crate::instance::Instance::enumerate_physical_devices
//! [`PhysicalDevice`]: crate::device::physical::PhysicalDevice
//! [`Device`]: crate::device::Device
//! [`Queue`]: crate::device::Queue
//! [`Swapchain`]: crate::swapchain::Swapchain
//! [*command buffer*]: crate::command_buffer
//! [*Buffers*]: crate::buffer
//! [*Images*]: crate::image
//! [*Pipelines*]: crate::pipeline
//! [*shader*]: crate::shader
//! [`ComputePipeline`]: crate::pipeline::ComputePipeline
//! [`GraphicsPipeline`]: crate::pipeline::GraphicsPipeline
//! [*Descriptor sets*]: crate::descriptor_set
//! [`DescriptorSetLayout`]: crate::descriptor_set::layout
//! [`PipelineLayout`]: crate::pipeline::layout
//! [`RenderPass`]: crate::render_pass::RenderPass
//! [`Framebuffer`]: crate::render_pass::Framebuffer
//! [`vulkano-macros`]: vulkano_macros
//! [`serde`]: https://crates.io/crates/serde

//#![warn(missing_docs)]        // TODO: activate
#![warn(
    rust_2018_idioms,
    rust_2021_compatibility,
    clippy::trivially_copy_pass_by_ref
)]
// These lints are a bit too pedantic, so they're disabled here.
#![allow(
    clippy::arc_with_non_send_sync,
    clippy::collapsible_else_if,
    clippy::collapsible_if,
    clippy::derivable_impls, // TODO: remove
    clippy::large_enum_variant,
    clippy::len_without_is_empty,
    clippy::missing_safety_doc, // TODO: remove
    clippy::module_inception,
    clippy::mutable_key_type,
    clippy::needless_borrowed_reference,
    clippy::new_without_default,
    clippy::nonminimal_bool,
    clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error
    clippy::result_large_err,
    clippy::too_many_arguments,
    clippy::type_complexity,
    clippy::vec_box,
    clippy::wrong_self_convention
)]

pub use ash::vk::Handle;
use bytemuck::{Pod, Zeroable};
pub use half;
pub use library::{LoadingError, VulkanLibrary};
use std::{
    borrow::Cow,
    error::Error,
    fmt::{Debug, Display, Error as FmtError, Formatter},
    num::NonZeroU64,
    ops::Deref,
    sync::Arc,
};
pub use {extensions::ExtensionProperties, version::Version};

#[macro_use]
mod tests;
#[macro_use]
mod extensions;
pub mod acceleration_structure;
pub mod buffer;
pub mod command_buffer;
pub mod deferred;
pub mod descriptor_set;
pub mod device;
pub mod display;
pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
mod cache;
mod fns;
pub mod image;
pub mod instance;
pub mod library;
mod macros;
pub mod memory;
pub mod padded;
pub mod pipeline;
pub mod query;
mod range_map;
pub mod range_set;
pub mod shader;
pub mod swapchain;
pub mod sync;

/// Represents memory size and offset values on a Vulkan device.
/// Analogous to the Rust `usize` type on the host.
pub use ash::vk::DeviceSize;

/// A [`DeviceSize`] that is known not to equal zero.
pub type NonZeroDeviceSize = NonZeroU64;

/// Represents an address (pointer) on a Vulkan device.
pub use ash::vk::DeviceAddress;

/// A [`DeviceAddress`] that is known not to equal zero.
pub type NonNullDeviceAddress = NonZeroU64;

/// Holds 24 bits in the least significant bits of memory,
/// and 8 bytes in the most significant bits of that memory,
/// occupying a single [`u32`] in total.
// NOTE: This is copied from Ash, but duplicated here so that we can implement traits on it.
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Zeroable, Pod)]
#[repr(transparent)]
pub struct Packed24_8(u32);

impl Packed24_8 {
    /// Returns a new `Packed24_8` value.
    #[inline]
    pub fn new(low_24: u32, high_8: u8) -> Self {
        Self((low_24 & 0x00ff_ffff) | (u32::from(high_8) << 24))
    }

    /// Returns the least-significant 24 bits (3 bytes) of this integer.
    #[inline]
    pub fn low_24(&self) -> u32 {
        self.0 & 0xffffff
    }

    /// Returns the most significant 8 bits (single byte) of this integer.
    #[inline]
    pub fn high_8(&self) -> u8 {
        (self.0 >> 24) as u8
    }
}

// Allow refering to crate by its name to work around limitations of proc-macros
// in doctests.
// See https://github.com/rust-lang/cargo/issues/9886
// and https://github.com/bkchr/proc-macro-crate/issues/10
#[allow(unused_extern_crates)]
extern crate self as vulkano;

/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
unsafe impl<T: ?Sized> SafeDeref for Box<T> {}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Handle: ash::vk::Handle;

    /// Returns the raw Vulkan handle of the object.
    fn handle(&self) -> Self::Handle;
}

unsafe impl<T, U> VulkanObject for T
where
    T: SafeDeref<Target = U>,
    U: VulkanObject + ?Sized,
{
    type Handle = U::Handle;

    #[inline]
    fn handle(&self) -> Self::Handle {
        (**self).handle()
    }
}

/// A wrapper that displays only the contained object's type and handle when debug-formatted. This
/// is useful because we have a lot of dependency chains, and the same dependencies would otherwise
/// be debug-formatted along with the dependents over and over leading to royal levels of spam.
#[repr(transparent)]
struct DebugWrapper<T>(T);

impl<T> Debug for DebugWrapper<T>
where
    T: Debug + VulkanObject,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        write!(f, "0x{:x}", self.0.handle().as_raw())
    }
}

impl<T> Deref for DebugWrapper<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/errors.rs"));

impl Error for VulkanError {}

impl Display for VulkanError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        let msg = match self {
            VulkanError::NotReady => "a resource is not yet ready",
            VulkanError::Timeout => "an operation has not completed in the specified time",
            VulkanError::OutOfHostMemory => "a host memory allocation has failed",
            VulkanError::OutOfDeviceMemory => "a device memory allocation has failed",
            VulkanError::InitializationFailed => {
                "initialization of an object could not be completed for implementation-specific \
                reasons"
            }
            VulkanError::DeviceLost => "the logical or physical device has been lost",
            VulkanError::MemoryMapFailed => "mapping of a memory object has failed",
            VulkanError::LayerNotPresent => {
                "a requested layer is not present or could not be loaded"
            }
            VulkanError::ExtensionNotPresent => "a requested extension is not supported",
            VulkanError::FeatureNotPresent => "a requested feature is not supported",
            VulkanError::IncompatibleDriver => {
                "the requested version of Vulkan is not supported by the driver or is otherwise \
                incompatible for implementation-specific reasons"
            }
            VulkanError::TooManyObjects => "too many objects of the type have already been created",
            VulkanError::FormatNotSupported => "a requested format is not supported on this device",
            VulkanError::FragmentedPool => {
                "a pool allocation has failed due to fragmentation of the pool's memory"
            }
            VulkanError::Unknown => {
                "an unknown error has occurred; either the application has provided invalid input, \
                or an implementation failure has occurred"
            }
            VulkanError::OutOfPoolMemory => "a pool memory allocation has failed",
            VulkanError::InvalidExternalHandle => {
                "an external handle is not a valid handle of the specified type"
            }
            VulkanError::Fragmentation => {
                "a descriptor pool creation has failed due to fragmentation"
            }
            VulkanError::InvalidOpaqueCaptureAddress => {
                "a buffer creation or memory allocation failed because the requested address is \
                not available. A shader group handle assignment failed because the requested \
                shader group handle information is no longer valid"
            }
            VulkanError::IncompatibleDisplay => {
                "the display used by a swapchain does not use the same presentable image layout, \
                or is incompatible in a way that prevents sharing an image"
            }
            VulkanError::NotPermitted => "a requested operation was not permitted",
            VulkanError::SurfaceLost => "a surface is no longer available",
            VulkanError::NativeWindowInUse => {
                "the requested window is already in use by Vulkan or another API in a manner which \
                prevents it from being used again"
            }
            VulkanError::OutOfDate => {
                "a surface has changed in such a way that it is no longer compatible with the \
                swapchain, and further presentation requests using the swapchain will fail"
            }
            VulkanError::InvalidVideoStdParameters => {
                "the provided Video Std parameters do not adhere to the requirements of the used \
                video compression standard"
            }
            VulkanError::ValidationFailed => "validation failed",
            VulkanError::FullScreenExclusiveModeLost => {
                "an operation on a swapchain created with application controlled full-screen \
                access failed as it did not have exclusive full-screen access"
            }
            VulkanError::InvalidDrmFormatModifierPlaneLayout => {
                "the requested DRM format modifier plane layout is invalid"
            }
            VulkanError::InvalidShader => "one or more shaders failed to compile or link",
            VulkanError::ImageUsageNotSupported => "the requested `ImageUsage` are not supported",
            VulkanError::VideoPictureLayoutNotSupported => {
                "the requested video picture layout is not supported"
            }
            VulkanError::VideoProfileOperationNotSupported => {
                "a video profile operation specified via `VideoProfileInfo::video_codec_operation` \
                is not supported"
            }
            VulkanError::VideoProfileFormatNotSupported => {
                "format parameters in a requested `VideoProfileInfo` chain are not supported"
            }
            VulkanError::VideoProfileCodecNotSupported => {
                "codec-specific parameters in a requested `VideoProfileInfo` chain are not \
                supported"
            }
            VulkanError::VideoStdVersionNotSupported => {
                "the specified video Std header version is not supported"
            }
            VulkanError::CompressionExhausted => {
                "an image creation failed because internal resources required for compression are \
                exhausted"
            }
            VulkanError::Unnamed(result) => {
                return write!(f, "unnamed error, VkResult value {}", result.as_raw());
            }
        };

        write!(f, "{msg}")
    }
}

impl From<VulkanError> for Validated<VulkanError> {
    fn from(err: VulkanError) -> Self {
        Self::Error(err)
    }
}

/// A wrapper for error types of functions that can return validation errors.
#[derive(Clone)]
pub enum Validated<E> {
    /// A non-validation error occurred.
    Error(E),

    /// A validation error occurred.
    ValidationError(Box<ValidationError>),
}

impl<E> Validated<E> {
    /// Maps the inner `Error` value using the provided function, or does nothing if the value is
    /// `ValidationError`.
    pub fn map<F>(self, f: impl FnOnce(E) -> F) -> Validated<F> {
        match self {
            Self::Error(err) => Validated::Error(f(err)),
            Self::ValidationError(err) => Validated::ValidationError(err),
        }
    }

    fn map_validation(self, f: impl FnOnce(Box<ValidationError>) -> Box<ValidationError>) -> Self {
        match self {
            Self::Error(err) => Self::Error(err),
            Self::ValidationError(err) => Self::ValidationError(f(err)),
        }
    }

    /// Returns the inner `Error` value, or panics if it contains `ValidationError`.
    pub fn unwrap(self) -> E {
        match self {
            Self::Error(err) => err,
            Self::ValidationError(err) => {
                panic!(
                    "called `Validated::unwrap` on a `ValidationError` value: {:?}",
                    err
                )
            }
        }
    }
}

impl<E> Error for Validated<E>
where
    E: Error + 'static,
{
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            Self::Error(err) => Some(err),
            Self::ValidationError(err) => Some(err),
        }
    }
}

impl<E> Display for Validated<E> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        match self {
            Self::Error(_) => write!(f, "a non-validation error occurred"),
            Self::ValidationError(_) => write!(f, "a validation error occurred"),
        }
    }
}

impl<E> Debug for Validated<E>
where
    E: Display,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        match self {
            Self::Error(err) => write!(f, "a non-validation error occurred: {err}"),
            Self::ValidationError(err) => {
                write!(f, "a validation error occurred\n\nCaused by:\n    {err:?}")
            }
        }
    }
}

impl<E> From<Box<ValidationError>> for Validated<E> {
    fn from(err: Box<ValidationError>) -> Self {
        Self::ValidationError(err)
    }
}

/// The arguments or other context of a call to a Vulkan function were not valid.
#[derive(Clone, Default)]
pub struct ValidationError {
    /// The context in which the problem exists (e.g. a specific parameter).
    pub context: Cow<'static, str>,

    /// A description of the problem.
    pub problem: Cow<'static, str>,

    /// If applicable, settings that the user could enable to avoid the problem in the future.
    pub requires_one_of: RequiresOneOf,

    /// *Valid Usage IDs* (VUIDs) in the Vulkan specification that relate to the problem.
    pub vuids: &'static [&'static str],
}

impl ValidationError {
    fn from_error<E: Error>(err: E) -> Self {
        Self {
            context: "".into(),
            problem: err.to_string().into(),
            requires_one_of: RequiresOneOf::default(),
            vuids: &[],
        }
    }

    fn add_context(mut self: Box<Self>, context: impl Into<Cow<'static, str>>) -> Box<Self> {
        if self.context.is_empty() {
            self.context = context.into();
        } else {
            self.context = format!("{}.{}", context.into(), self.context).into();
        }

        self
    }

    fn set_vuids(mut self: Box<Self>, vuids: &'static [&'static str]) -> Box<Self> {
        self.vuids = vuids;
        self
    }
}

impl Debug for ValidationError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        if self.context.is_empty() {
            write!(f, "{}", self.problem)?;
        } else {
            write!(f, "{}: {}", self.context, self.problem)?;
        }

        if !self.requires_one_of.is_empty() {
            if self.context.is_empty() && self.problem.is_empty() {
                write!(f, "{:?}", self.requires_one_of)?;
            } else {
                write!(f, "\n\n{:?}", self.requires_one_of)?;
            }
        }

        if !self.vuids.is_empty() {
            write!(f, "\n\nVulkan VUIDs:")?;

            for vuid in self.vuids {
                write!(f, "\n    {}", vuid)?;
            }
        }

        Ok(())
    }
}

impl Display for ValidationError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        if self.context.is_empty() {
            write!(f, "{}", self.problem)?;
        } else {
            write!(f, "{}: {}", self.context, self.problem)?;
        }

        if !self.requires_one_of.is_empty() {
            if self.problem.is_empty() {
                write!(f, "{}", self.requires_one_of)?;
            } else {
                write!(f, " -- {}", self.requires_one_of)?;
            }
        }

        if let Some((first, rest)) = self.vuids.split_first() {
            write!(f, " (Vulkan VUIDs: {}", first)?;

            for vuid in rest {
                write!(f, ", {}", vuid)?;
            }

            write!(f, ")")?;
        }

        Ok(())
    }
}

impl Error for ValidationError {}

/// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow
/// a given operation.
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct RequiresOneOf(pub &'static [RequiresAllOf]);

impl RequiresOneOf {
    /// Returns the number of alternatives.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns whether there are any alternatives.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl Debug for RequiresOneOf {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        write!(f, "Requires one of:")?;

        for requires_all_of in self.0 {
            write!(f, "\n    {}", requires_all_of)?;
        }

        Ok(())
    }
}

impl Display for RequiresOneOf {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        write!(f, "requires one of: ")?;

        if let Some((first, rest)) = self.0.split_first() {
            if first.0.len() > 1 {
                write!(f, "({})", first)?;
            } else {
                write!(f, "{}", first)?;
            }

            for rest in rest {
                if first.0.len() > 1 {
                    write!(f, " or ({})", rest)?;
                } else {
                    write!(f, " or {}", rest)?;
                }
            }
        }

        Ok(())
    }
}

/// Used in errors to indicate a set of requirements that all need to be available/enabled to allow
/// a given operation.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RequiresAllOf(pub &'static [Requires]);

impl Display for RequiresAllOf {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        if let Some((first, rest)) = self.0.split_first() {
            write!(f, "{}", first)?;

            for rest in rest {
                write!(f, " + {}", rest)?;
            }
        }

        Ok(())
    }
}

/// Something that needs to be supported or enabled to allow a particular operation.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Requires {
    APIVersion(Version),
    Feature(&'static str),
    DeviceExtension(&'static str),
    InstanceExtension(&'static str),
}

impl Display for Requires {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
        match self {
            Requires::APIVersion(Version { major, minor, .. }) => {
                write!(f, "Vulkan API version {}.{}", major, minor)
            }
            Requires::Feature(feature) => write!(f, "feature `{}`", feature),
            Requires::DeviceExtension(device_extension) => {
                write!(f, "device extension `{}`", device_extension)
            }
            Requires::InstanceExtension(instance_extension) => {
                write!(f, "instance extension `{}`", instance_extension)
            }
        }
    }
}

/// A helper type for non-exhaustive structs.
///
/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only
/// be constructed by calling a constructor function or `Default::default()`. The effect is similar
/// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update
/// syntax from being used.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed
pub struct NonExhaustive(pub(crate) ());