vulkayes_core/util/macros.rs
1//! Macros galore!
2
3/// Generates a private enum and a public newtype struct that only has that enum as a value.
4/// Also generated constructors on the struct that match the enum variants.
5///
6/// This is useful for making certain enum variants "unsafe" by only allowing their construction using
7/// an unsafe function. Variants may also be private.
8///
9/// Since a common usecase across this crate for this macro are typesafe parameter combinations, there
10/// is also a version with `Into` implementation.
11///
12/// Tuple enum variants are not supported.
13///
14/// Usage:
15/// ```
16/// # #[macro_use] extern crate vulkayes_core;
17/// unsafe_enum_variants! {
18/// #[derive(Debug)]
19/// enum UnsafeEnumInner ['a] {
20/// /// Private
21/// Foo => { &0u32 },
22/// /// Public
23/// pub Bar => { &1u32 },
24/// /// Unsafe and generic
25/// {unsafe} pub Qux { num: &'a u32 } => { num }
26/// } as pub UnsafeEnum ['a] impl Into<&'a u32>
27/// }
28/// ```
29///
30/// expands to:
31/// ```
32/// #[derive(Debug)]
33/// enum UnsafeEnumInner<'a> {
34/// Foo,
35/// Bar,
36/// Qux {
37/// num: &'a u32
38/// }
39/// }
40/// #[derive(Debug)]
41/// pub struct UnsafeEnum<'a>(UnsafeEnumInner<'a>);
42/// impl<'a> UnsafeEnum<'a> {
43/// #[doc = r###"Private"###]
44/// #[allow(non_snake_case)]
45/// const fn Foo() -> Self {
46/// UnsafeEnum(UnsafeEnumInner::Foo)
47/// }
48/// #[doc = r###"Public"###]
49/// #[allow(non_snake_case)]
50/// pub const fn Bar() -> Self {
51/// UnsafeEnum(UnsafeEnumInner::Bar)
52/// }
53/// #[doc = r###"Unsafe"###]
54/// #[allow(non_snake_case)]
55/// pub const unsafe fn Qux(num: &'a u32) -> Self {
56/// UnsafeEnum(UnsafeEnumInner::Qux { num })
57/// }
58/// }
59/// impl<'a> Into<&'a u32> for UnsafeEnum<'a> {
60/// fn into(self) -> &'a u32 {
61/// match self.0 {
62/// UnsafeEnumInner::Foo => { &0u32 },
63/// UnsafeEnumInner::Bar => { &1u32 },
64/// UnsafeEnumInner::Qux { num } => { num }
65/// }
66/// }
67/// }
68/// ```
69#[macro_export]
70macro_rules! unsafe_enum_variants {
71 (
72 $(#[$attribute: meta])*
73 enum $inner_name: ident $([ $($generic_bounds: tt)+ ])? {
74 $(
75 $(#[$variant_attribute: meta])*
76 $({$safety: tt})? $v: vis $variant: ident $({
77 $($variant_name: ident: $variant_type: ty),+ $(,)?
78 })? => { $($into_code: tt)+ }
79 ),+ $(,)?
80 } as pub $name: ident $([ $($generic_params: tt)+ ])? impl Into<$into_type: ty>
81 ) => {
82 unsafe_enum_variants!(
83 $(#[$attribute])*
84 enum $inner_name $([ $($generic_bounds)+ ])? {
85 $(
86 $(#[$variant_attribute])*
87 $({$safety})? $v $variant $({ $($variant_name: $variant_type),+ })?
88 ),+
89 } as pub $name $([ $($generic_params)+ ])?
90 );
91 impl $(< $($generic_bounds)+ >)? Into<$into_type> for $name $(< $($generic_params)+ >)? {
92 fn into(self) -> $into_type {
93 #[allow(unused_doc_comments)]
94 match self.0 {
95 $(
96 $(#[$variant_attribute])*
97 $inner_name::$variant $({ $($variant_name),+ })? => { $($into_code)+ }
98 ),+
99 }
100 }
101 }
102 };
103
104 (
105 $(#[$attribute: meta])*
106 enum $inner_name: ident $([ $($generic_bounds: tt)+ ])? {
107 $(
108 $(#[$variant_attribute: meta])*
109 $({$safety: tt})? $v: vis $variant: ident $({
110 $($variant_name: ident: $variant_type: ty),+ $(,)?
111 })?
112 ),+ $(,)?
113 } as pub $name: ident $([ $($generic_params: tt)+ ])?
114 ) => {
115 $(#[$attribute])*
116 enum $inner_name $(< $($generic_bounds)+ >)? {
117 $(
118 $(#[$variant_attribute])*
119 $variant $({
120 $($variant_name: $variant_type),+
121 })?
122 ),+
123 }
124 $(#[$attribute])*
125 pub struct $name $(< $($generic_bounds)+ >)? ($inner_name $(< $($generic_params)+ >)?);
126 impl $(< $($generic_bounds)+ >)? $name $(< $($generic_params)+ >)? {
127 $(
128 $(#[$variant_attribute])*
129 #[allow(non_snake_case)]
130 $v const $($safety)? fn $variant($( $( $variant_name: $variant_type ),+ )?) -> Self {
131 $name(
132 #[allow(unused_doc_comments)]
133 $(#[$variant_attribute])*
134 $inner_name::$variant $({ $($variant_name),+ })?
135 )
136 }
137 )*
138 }
139 };
140}
141
142/// Wraps an ash builder in a `#[repr(transparent)]` struct.
143///
144/// Usage:
145/// ```
146/// # use vulkayes_core::vk_builder_wrap;
147/// # #[repr(transparent)]
148/// # pub struct BuilderType<'a>(BuilderTargetType, std::marker::PhantomData<&'a ()>);
149/// # impl<'a> std::ops::Deref for BuilderType<'a> { type Target = BuilderTargetType; fn deref(&self) -> &Self::Target { &self.0 } }
150/// # #[derive(Debug)]
151/// # pub struct BuilderTargetType(u32);
152///
153/// vk_builder_wrap! {
154/// /// Doc comment
155/// pub struct Foo ['a] {
156/// // the `=> BuilderTargetType` part is optional and generates an additional Transparent unsafe impl
157/// builder: BuilderType<'a> => BuilderTargetType
158/// }
159/// impl ['a] {
160/// pub fn new(param: &'a u32) -> Self {
161/// todo!()
162/// }
163/// }
164/// }
165/// ```
166///
167/// expands to:
168/// ```
169/// # #[repr(transparent)]
170/// # pub struct BuilderType<'a>(BuilderTargetType, std::marker::PhantomData<&'a ()>);
171/// # impl<'a> std::ops::Deref for BuilderType<'a> { type Target = BuilderTargetType; fn deref(&self) -> &Self::Target { &self.0 } }
172/// # #[derive(Debug)]
173/// # pub struct BuilderTargetType(u32);
174///
175/// #[doc = r###"Doc comment"###]
176/// #[repr(transparent)]
177/// pub struct Foo<'a> {
178/// builder: BuilderType<'a>
179/// }
180/// impl<'a> Foo<'a> {
181/// pub const unsafe fn from_raw(
182/// builder: BuilderType<'a>
183/// ) -> Self {
184/// Foo {
185/// builder
186/// }
187/// }
188///
189/// pub fn new(param: &'a u32) -> Self { todo!() }
190/// }
191/// impl<'a> std::ops::Deref for Foo<'a> {
192/// type Target = BuilderType<'a>;
193///
194/// fn deref(&self) -> &Self::Target {
195/// &self.builder
196/// }
197/// }
198/// impl<'a> std::ops::DerefMut for Foo<'a> {
199/// fn deref_mut(&mut self) -> &mut Self::Target {
200/// &mut self.builder
201/// }
202/// }
203/// unsafe impl<'a> vulkayes_core::util::transparent::Transparent for Foo<'a> {
204/// type Target = BuilderType<'a>;
205/// }
206/// // This is optional
207/// unsafe impl<'a> vulkayes_core::util::transparent::Transparent for BuilderType<'a> {
208/// type Target = BuilderTargetType
209/// ;
210/// }
211/// impl<'a> std::fmt::Debug for Foo<'a> {
212/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
213/// f.debug_struct(stringify!( Foo ))
214/// .field("self.builder.deref()", std::ops::Deref::deref(&self.builder))
215/// .finish()
216/// }
217/// }
218/// ```
219#[macro_export]
220macro_rules! vk_builder_wrap {
221 (
222 $(#[$attribute: meta])*
223 pub struct $name: ident $([ $($generic_bounds: tt)+ ])? {
224 builder: $target: ty $(=> $vk_target: ty)?
225 }
226 impl $([ $($generic_params: tt)+ ])? {
227 $(
228 $impl_code: tt
229 )+
230 }
231 ) => {
232 $(#[$attribute])*
233 #[repr(transparent)]
234 pub struct $name $(< $($generic_bounds)+ >)? {
235 builder: $target
236 }
237 impl $(< $($generic_bounds)+ >)? $name $(< $($generic_params)+ >)? {
238 pub const unsafe fn from_raw(
239 builder: $target
240 ) -> Self {
241 $name {
242 builder
243 }
244 }
245
246 $(
247 $impl_code
248 )+
249 }
250 impl $(< $($generic_bounds)+ >)? std::ops::Deref for $name $(< $($generic_params)+ >)? {
251 type Target = $target;
252
253 fn deref(&self) -> &Self::Target {
254 &self.builder
255 }
256 }
257 impl $(< $($generic_bounds)+ >)? std::ops::DerefMut for $name $(< $($generic_params)+ >)? {
258 fn deref_mut(&mut self) -> &mut Self::Target {
259 &mut self.builder
260 }
261 }
262 unsafe impl $(< $($generic_bounds)+ >)? $crate::util::transparent::Transparent for $name $(< $($generic_params)+ >)? {
263 type Target = $target;
264 }
265 $(
266 unsafe impl<'a> $crate::util::transparent::Transparent for $target {
267 type Target = $vk_target;
268 }
269 )?
270 impl $(< $($generic_bounds)+ >)? std::fmt::Debug for $name $(< $($generic_params)+ >)? {
271 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
272 f.debug_struct(stringify!($name))
273 .field("self.builder.deref()", std::ops::Deref::deref(&self.builder))
274 .finish()
275 }
276 }
277 }
278}
279
280/// Generates a public enum that derives `thiserror::Error` with `VkResult` variants and their `From` impls.
281///
282/// Usage:
283/// ```
284/// # #[macro_use] extern crate vulkayes_core;
285/// trait Trait: std::error::Error + 'static {}
286///
287/// vk_result_error! {
288/// #[derive(Debug)]
289/// pub enum ImageError [A] where [A: Trait] {
290/// vk {
291/// ERROR_OUT_OF_HOST_MEMORY,
292/// ERROR_OUT_OF_DEVICE_MEMORY
293/// }
294///
295/// #[error("Description")]
296/// Other(#[from] A)
297/// }
298/// }
299/// ```
300///
301/// expands to:
302/// ```
303/// # trait Trait: std::error::Error + 'static {}
304/// // ...
305///
306/// #[allow(unused_imports)]
307/// use thiserror::*;
308///
309/// #[derive(Debug)]
310/// #[derive(Error)]
311/// pub enum ImageError<A: Trait> {
312/// #[error("{}", ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY)]
313/// #[allow(non_camel_case_types)]
314/// ERROR_OUT_OF_HOST_MEMORY,
315/// #[error("{}", ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY)]
316/// #[allow(non_camel_case_types)]
317/// ERROR_OUT_OF_DEVICE_MEMORY,
318///
319/// #[error("Description")]
320/// Other(#[from] A)
321/// }
322/// impl<A: Trait> From<ash::vk::Result> for ImageError<A> {
323/// fn from(err: ash::vk::Result) -> Self {
324/// match err {
325/// ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => ImageError::ERROR_OUT_OF_HOST_MEMORY,
326/// ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => ImageError::ERROR_OUT_OF_DEVICE_MEMORY,
327/// _ => unreachable!("Cannot create {} from {}", stringify!(ImageError), err)
328/// }
329/// }
330/// }
331/// ```
332#[macro_export]
333macro_rules! vk_result_error {
334 (
335 $( #[$attribute: meta] )*
336 pub enum $name: ident $([ $($generic_params: tt)+ ] where [ $($generic_bounds: tt)+ ])? {
337 vk {
338 $(
339 $( #[$variant_attribute: meta] )*
340 $vk_error: ident
341 ),+ $(,)?
342 }
343 $( $other: tt )*
344 }
345 ) => {
346 #[allow(unused_imports)]
347 use thiserror::*;
348
349 $( #[$attribute] )*
350 #[derive(Error)]
351 pub enum $name $(< $($generic_bounds)+ >)? {
352 $(
353 $( #[$variant_attribute] )*
354 #[error("{}", ash::vk::Result::$vk_error)]
355 #[allow(non_camel_case_types)]
356 $vk_error,
357 )+
358
359 $( $other )*
360 }
361 impl $(< $($generic_bounds)+ >)? From<ash::vk::Result> for $name $(< $($generic_params)+ >)? {
362 fn from(err: ash::vk::Result) -> Self {
363 match err {
364 $(
365 ash::vk::Result::$vk_error => $name::$vk_error,
366 )+
367 _ => unreachable!("Cannot create {} from {}", stringify!($name), err)
368 }
369 }
370 }
371 }
372}
373
374/// Implements `Borrow`, `Deref`, `PartialEq`, `Eq`, `Hash`, `PartialOrd` and `Ord` for a type based on its `Borrow` implementation.
375///
376/// This macro is closely tied to the `HasHandle` and `HasSynchronizedHandle` traits.
377///
378/// There are three variants of this macro:
379/// ```
380/// # #[macro_use] extern crate vulkayes_core;
381/// # use std::fmt::Debug;
382/// # use vulkayes_core::prelude::Vutex;
383/// # use vulkayes_core::ash::vk;
384/// #
385/// # struct Foo;
386/// # impl Foo {
387/// # fn handle(&self) -> vk::Image {
388/// # unimplemented!()
389/// # }
390/// # }
391/// # type Target = Foo;
392///
393/// struct MyType<A> {
394/// field_on_self: Target,
395/// other_field: A
396/// }
397///
398/// // Base variant
399/// // Deref is optional. If it is not desired, the `<Target>` token is appended to `Borrow` instead.
400/// impl_common_handle_traits! {
401/// impl [A: Debug] Deref<Target>, Borrow, Eq, Hash, Ord for MyType<A> {
402/// target = { field_on_self } // Borrows and Derefs to `Target` by invoking `&self.field_on_self`
403///
404/// to_handle { .handle() } // Gets a handle from `Target` by invoking `self.field_on_self.handle()`
405/// }
406/// }
407///
408/// // HasHandle variant
409/// // struct MyType<A> {
410/// // field_on_self: vk::Image,
411/// // other_field: A
412/// // }
413/// // impl_common_handle_traits! {
414/// // impl [A: Debug] HasHandle<Target>, Deref, Borrow, Eq, Hash, Ord for MyType<A> {
415/// // target = { field_on_self }
416/// // }
417/// // }
418///
419/// // HasSynchronizedHandle variant
420/// // struct MyType<A> {
421/// // field_on_self: Vutex<vk::Image>,
422/// // other_field: A
423/// // }
424/// // impl_common_handle_traits! {
425/// // impl [A: Debug] HasSynchronizedHandle<Target>, Deref, Borrow, Eq, Hash, Ord for MyType<A> {
426/// // target = { field_on_self }
427/// // }
428/// // }
429/// ```
430///
431/// expands to:
432/// ```
433/// # use std::fmt::Debug;
434/// # use vulkayes_core::prelude::Vutex;
435/// # use vulkayes_core::ash::vk;
436/// #
437/// # struct Foo;
438/// # impl Foo {
439/// # fn handle(&self) -> vk::Image {
440/// # unimplemented!()
441/// # }
442/// # }
443/// # type Target = Foo;
444/// #
445/// # struct MyType<A> {
446/// # field_on_self: Target,
447/// # other_field: A
448/// # }
449/// // ...
450///
451/// // Base variant
452/// // Deref is optional
453/// impl<A: Debug> std::ops::Deref for MyType<A> {
454/// type Target = Target;
455///
456/// fn deref(&self) -> &Self::Target {
457/// &self.field_on_self
458/// }
459/// }
460/// impl<A: Debug> std::borrow::Borrow<Target> for MyType<A> {
461/// fn borrow(&self) -> &Target {
462/// &self.field_on_self
463/// }
464/// }
465///
466/// impl<A: Debug> PartialEq for MyType<A> {
467/// fn eq(&self, other: &Self) -> bool {
468/// self.field_on_self.handle() == other.field_on_self.handle()
469/// }
470/// }
471/// impl<A: Debug> Eq for MyType<A> {}
472/// impl<A: Debug> std::hash::Hash for MyType<A> {
473/// fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
474/// self.field_on_self.handle().hash(state)
475/// }
476/// }
477///
478/// impl<A: Debug> std::cmp::PartialOrd for MyType<A> {
479/// fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
480/// self.field_on_self.handle().partial_cmp(&other.field_on_self.handle())
481/// }
482/// }
483/// impl<A: Debug> std::cmp::Ord for MyType<A> {
484/// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
485/// self.field_on_self.handle().cmp(&other.field_on_self.handle())
486/// }
487/// }
488///
489/// // HasHandle variant adds to the previous implementations also:
490/// // impl<A: Debug> vulkayes_core::util::handle::HasHandle<vk::Image> for MyType<A> {}
491///
492/// // While HasSynchronizedHandle adds:
493/// // impl<A: Debug> vulkayes_core::util::handle::HasSynchronizedHandle<vk::Image> for MyType<A> {}
494/// ```
495#[macro_export]
496macro_rules! impl_common_handle_traits {
497 (
498 impl $([ $($impl_gen: tt)+ ])? HasHandle<$target: ty>, Deref, Borrow, Eq, Hash, Ord for $tp: ty {
499 target = { $($target_code: tt)+ }
500 } $(+ $deref: ident)?
501 ) => {
502 impl_common_handle_traits!(
503 impl $([ $($impl_gen)+ ])? Deref<$target>, Borrow, Eq, Hash, Ord for $tp {
504 target = { $($target_code)+ }
505 }
506 );
507 impl $crate::util::handle::HasHandle<$target> for $tp {}
508 };
509 (
510 impl $([ $($impl_gen: tt)+ ])? HasHandle<$target: ty>, Borrow, Eq, Hash, Ord for $tp: ty {
511 target = { $($target_code: tt)+ }
512 }
513 ) => {
514 impl_common_handle_traits!(
515 impl $([ $($impl_gen)+ ])? Borrow<$target>, Eq, Hash, Ord for $tp {
516 target = { $($target_code)+ }
517 }
518 );
519 impl $crate::util::handle::HasHandle<$target> for $tp {}
520 };
521
522 (
523 impl $([ $($impl_gen: tt)+ ])? HasSynchronizedHandle<$target: ty>, Deref, Borrow, Eq, Hash, Ord for $tp: ty {
524 target = { $($target_code: tt)+ }
525 }
526 ) => {
527 impl_common_handle_traits!(
528 impl $([ $($impl_gen)+ ])? Deref<$crate::util::sync::Vutex<$target>>, Borrow, Eq, Hash, Ord for $tp {
529 target = { $($target_code)+ }
530
531 to_handle { .lock().expect("vutex poisoned").deref() }
532 }
533 );
534 impl $crate::util::handle::HasSynchronizedHandle<$target> for $tp {}
535 };
536 (
537 impl $([ $($impl_gen: tt)+ ])? HasSynchronizedHandle<$target: ty>, Borrow, Eq, Hash, Ord for $tp: ty {
538 target = { $($target_code: tt)+ }
539 }
540 ) => {
541 impl_common_handle_traits!(
542 impl $([ $($impl_gen)+ ])? Borrow<$crate::util::sync::Vutex<$target>>, Eq, Hash, Ord for $tp {
543 target = { $($target_code)+ }
544
545 to_handle { .lock().expect("vutex poisoned").deref() }
546 }
547 );
548 impl $crate::util::handle::HasSynchronizedHandle<$target> for $tp {}
549 };
550
551 (
552 impl $([ $($impl_gen: tt)+ ])? Deref<$target: ty>, Borrow, Eq, Hash, Ord for $tp: ty {
553 target = { $($target_code: tt)+ }
554
555 $(
556 to_handle { $($to_handle_code: tt)+ }
557 )?
558 }
559 ) => {
560 impl $(< $($impl_gen)+ >)? std::ops::Deref for $tp {
561 type Target = $target;
562
563 fn deref(&self) -> &Self::Target {
564 &self.$($target_code)+
565 }
566 }
567 impl_common_handle_traits!(
568 impl $([ $($impl_gen)+ ])? Borrow<$target>, Eq, Hash, Ord for $tp {
569 target = { $($target_code)+ }
570
571 $(
572 to_handle { $($to_handle_code)+ }
573 )?
574 }
575 );
576 };
577
578 (
579 impl $([ $($impl_gen: tt)+ ])? Borrow<$target: ty>, Eq, Hash, Ord for $tp: ty {
580 target = { $($target_code: tt)+ }
581
582 $(
583 to_handle { $($to_handle_code: tt)+ }
584 )?
585 }
586 ) => {
587 impl $(< $($impl_gen)+ >)? std::borrow::Borrow<$target> for $tp {
588 fn borrow(&self) -> &$target {
589 &self.$($target_code)+
590 }
591 }
592
593 impl $(< $($impl_gen)+ >)? PartialEq for $tp {
594 fn eq(&self, other: &Self) -> bool {
595 self.$($target_code)+$( $($to_handle_code)+ )? == other.$($target_code)+$( $($to_handle_code)+ )?
596 }
597 }
598 impl $(< $($impl_gen)+ >)? Eq for $tp {}
599 impl $(< $($impl_gen)+ >)? std::hash::Hash for $tp {
600 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
601 self.$($target_code)+$( $($to_handle_code)+ )?.hash(state)
602 }
603 }
604
605 impl $(< $($impl_gen)+ >)? std::cmp::PartialOrd for $tp {
606 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
607 self.$($target_code)+$( $($to_handle_code)+ )?.partial_cmp(&other.$($target_code)+$( $($to_handle_code)+ )?)
608 }
609 }
610 impl $(< $($impl_gen)+ >)? std::cmp::Ord for $tp {
611 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
612 self.$($target_code)+$( $($to_handle_code)+ )?.cmp(&other.$($target_code)+$( $($to_handle_code)+ )?)
613 }
614 }
615 }
616}
617
618/// Creates a `repr(C)` struct and a companion offsets struct which represents byte offsets of the fields.
619///
620/// ```
621/// # #[macro_use] extern crate vulkayes_core;
622/// offsetable_struct! {
623/// #[derive(Debug)]
624/// pub struct Name {
625/// pub a: f32,
626/// pub b: [f32; 4],
627/// c: u8
628/// } repr(C) as NameOffsets
629/// }
630/// ```
631///
632/// expands to:
633/// ```
634/// #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
635/// pub struct NameOffsets {
636/// pub a: usize,
637/// pub b: usize,
638/// c: usize
639/// }
640///
641/// #[derive(Debug)]
642/// #[repr(C)]
643/// pub struct Name {
644/// pub a: f32,
645/// pub b: [f32; 4],
646/// c: u8
647/// }
648/// impl Name {
649/// #[allow(unused_variables)]
650/// pub const fn offsets() -> NameOffsets {
651/// let current_offset: usize = 0;
652///
653/// let a = vulkayes_core::util::align_up(current_offset, std::mem::align_of::<f32>());
654/// let current_offset = a + std::mem::size_of::<f32>();
655///
656/// let b = vulkayes_core::util::align_up(current_offset, std::mem::align_of::<[f32; 4]>());
657/// let current_offset = b + std::mem::size_of::<[f32; 4]>();
658///
659/// let c = vulkayes_core::util::align_up(current_offset, std::mem::align_of::<u8>());
660/// let current_offset = c + std::mem::size_of::<u8>();
661///
662/// NameOffsets {
663/// a,
664/// b,
665/// c
666/// }
667/// }
668/// }
669/// ```
670#[macro_export]
671macro_rules! offsetable_struct {
672 (
673 $( #[$attribute: meta] )*
674 $struct_vis: vis struct $name: ident {
675 $(
676 $field_vis: vis $field: ident: $ftype: ty
677 ),*
678 } repr(C) as $offsets_name: ident
679 ) => {
680 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
681 $struct_vis struct $offsets_name {
682 $(
683 $field_vis $field: usize
684 ),*
685 }
686
687 $( #[$attribute] )*
688 #[repr(C)]
689 $struct_vis struct $name {
690 $(
691 $field_vis $field: $ftype
692 ),*
693 }
694 impl $name {
695 /// Returns a struct describing offsets of each field from the start of the struct.
696 ///
697 /// This is mainly useful for things like vertex data
698 #[allow(unused_variables)]
699 pub const fn offsets() -> $offsets_name {
700 let current_offset: usize = 0;
701
702 $(
703 let $field = $crate::util::align_up(current_offset, std::mem::align_of::<$ftype>());
704 let current_offset = $field + std::mem::size_of::<$ftype>();
705 )*
706
707 $offsets_name {
708 $(
709 $field
710 ),*
711 }
712 }
713 }
714 }
715}
716
717/// Creates two fixed-size arrays. The first one holds locks and the second one holds deref of those locks.
718///
719/// This macro uses a `proc-macro-hack` version of the `seq-macro` crate to generate the array indices.
720///
721/// Usage:
722/// ```
723/// # #[macro_use] extern crate vulkayes_core;
724/// # use vulkayes_core::util::sync::{Vutex, VutexGuard};
725/// # #[derive(Debug)]
726/// # struct Bar;
727/// let foo = [Vutex::new(0), Vutex::new(1)];
728/// let bar: [Vutex<Bar>; 0] = [];
729/// lock_and_deref_closure!(
730/// let [foo; 2]{.lock().unwrap()} => |foo_locks, foo_derefs|
731/// let [bar; 0]{.lock().unwrap()} => |bar_locks: [VutexGuard<Bar>; 0], bar_derefs|
732/// {
733/// # let bar_derefs: [&Bar; 0] = bar_derefs;
734/// println!("{:?} {:?}", foo_derefs, bar_derefs);
735/// }
736/// )
737/// ```
738///
739/// expands to:
740/// ```
741/// # use vulkayes_core::util::sync::{Vutex, VutexGuard};
742/// # #[derive(Debug)]
743/// # struct Bar;
744/// # let foo = [Vutex::new(0), Vutex::new(1)];
745/// # let bar: [Vutex<Bar>; 0] = [];
746/// {
747/// let (foo_locks, foo_derefs) = {
748/// let locks = [foo[0].lock().unwrap(), foo[1].lock().unwrap()];
749/// let derefs = [*locks[0], *locks[1]];
750///
751/// (locks, derefs)
752/// };
753/// let (bar_locks, bar_derefs) = {
754/// let locks: [VutexGuard<Bar>; 0] = [];
755/// let derefs = [];
756///
757/// (locks, derefs)
758/// };
759///
760/// let closure = |foo_locks: [_; 2], foo_derefs: [_; 2], bar_locks: [_; 0], bar_derefs: [_; 0]| {
761/// # let bar_derefs: [&Bar; 0] = bar_derefs;
762/// println!("{:?} {:?}", foo_derefs, bar_derefs);
763/// };
764/// closure(foo_locks, foo_derefs, bar_locks, bar_derefs)
765/// }
766/// ```
767#[macro_export]
768macro_rules! lock_and_deref_closure {
769 (
770 $(
771 let [$ex: ident; $count: literal] {$($lock_code: tt)+} => |$locks: ident $(: $l_type: ty)?, $derefs: ident|
772 )+
773 { $($closure_body: tt)* }
774 ) => {
775 {
776 $(
777 let ($locks, $derefs) = $crate::seq_macro::seq!(
778 N in 0 .. $count {
779 {
780 let locks $(: $l_type)? = [ #( $ex[N] $($lock_code)+, )* ];
781 let derefs = [ #( *locks[N], )* ];
782
783 (locks, derefs)
784 }
785 }
786 );
787 )+
788
789 let closure = |$( $locks: [_; $count], $derefs: [_; $count] ),+| { $($closure_body)* };
790 closure($( $locks, $derefs ),+)
791 }
792 }
793}
794
795/// Simple enum dispatch using `Deref`. Suitable for mixed dispatch enums.
796///
797/// Usage:
798/// ```
799/// # #[macro_use] extern crate vulkayes_core;
800/// use std::{ops::Deref, rc::Rc};
801/// pub struct Baz;
802///
803/// #[derive(Debug, Clone)]
804/// pub struct Foo;
805/// impl Deref for Foo {
806/// type Target = Baz;
807/// #
808/// # fn deref(&self) -> &Self::Target {
809/// # &Baz
810/// # }
811/// }
812/// #[derive(Debug, Clone)]
813/// pub struct Bar;
814/// impl Deref for Bar {
815/// type Target = Baz;
816/// #
817/// # fn deref(&self) -> &Self::Target {
818/// # &Baz
819/// # }
820/// }
821/// trait Trait: Deref<Target = Baz> + std::fmt::Debug {}
822///
823/// deref_enum_dispatch! {
824/// /// Mixed-dispatch image enum.
825/// #[derive(Debug, Clone)]
826/// pub enum MixedDynTrait {
827/// Foo(Foo),
828/// Bar(Bar),
829/// Dyn(Rc<dyn Trait>)
830/// }: Deref<Target = Baz>
831/// }
832/// ```
833///
834/// expands to:
835/// ```
836/// # use std::{ops::Deref, rc::Rc};
837/// # pub struct Baz;
838/// # #[derive(Debug, Clone)]
839/// # pub struct Foo;
840/// # impl Deref for Foo {
841/// # type Target = Baz;
842/// #
843/// # fn deref(&self) -> &Self::Target {
844/// # &Baz
845/// # }
846/// # }
847/// # #[derive(Debug, Clone)]
848/// # pub struct Bar;
849/// # impl Deref for Bar {
850/// # type Target = Baz;
851/// #
852/// # fn deref(&self) -> &Self::Target {
853/// # &Baz
854/// # }
855/// # }
856/// # trait Trait: Deref<Target = Baz> + std::fmt::Debug {}
857/// // ...
858///
859/// /// Mixed-dispatch image enum.
860/// #[derive(Debug, Clone)]
861/// pub enum MixedDynTrait {
862/// Foo(Foo),
863/// Bar(Bar),
864/// Dyn(Rc<dyn Trait>)
865/// }
866/// impl Deref for MixedDynTrait {
867/// type Target = Baz;
868///
869/// fn deref(&self) -> &Self::Target {
870/// match self {
871/// MixedDynTrait::Foo(value) => value.deref(),
872/// MixedDynTrait::Bar(value) => value.deref(),
873/// MixedDynTrait::Dyn(value) => value.deref()
874/// }
875/// }
876/// }
877/// impl From<Foo> for MixedDynTrait {
878/// fn from(value: Foo) -> Self {
879/// MixedDynTrait::Foo(value)
880/// }
881/// }
882/// impl From<Bar> for MixedDynTrait {
883/// fn from(value: Bar) -> Self {
884/// MixedDynTrait::Bar(value)
885/// }
886/// }
887/// impl From<Rc<dyn Trait>> for MixedDynTrait {
888/// fn from(value: Rc<dyn Trait>) -> Self {
889/// MixedDynTrait::Dyn(value)
890/// }
891/// }
892/// ```
893#[macro_export]
894macro_rules! deref_enum_dispatch {
895 (
896 $( #[$attribute: meta] )*
897 $visibility: vis enum $name: ident {
898 $(
899 $variant: ident ($variant_payload: ty)
900 ),+
901 }: Deref<Target = $target: ty>
902 ) => {
903 $( #[$attribute] )*
904 $visibility enum $name {
905 $(
906 $variant ($variant_payload)
907 ),+
908 }
909 impl Deref for $name {
910 type Target = $target;
911
912 fn deref(&self) -> &Self::Target {
913 match self {
914 $(
915 $name::$variant(value) => value.deref()
916 ),+
917 }
918 }
919 }
920 $(
921 impl From<$variant_payload> for $name {
922 fn from(value: $variant_payload) -> Self {
923 $name::$variant(value)
924 }
925 }
926 )+
927 }
928}
929
930/// Creates a subset of a vk enum, which is defined as an i32 struct with associated constants.
931///
932/// Usage:
933/// ```
934/// # use vulkayes_core::vk_enum_subset;
935/// # mod vk {
936/// # #[derive(Debug, Eq, PartialEq)]
937/// # pub struct MainEnum(i32);
938/// # impl MainEnum {
939/// # pub const FOO: Self = MainEnum(0);
940/// # pub const BAR: Self = MainEnum(1);
941/// # pub const BAZ: Self = MainEnum(2);
942/// # pub const QUZ: Self = MainEnum(3);
943/// #
944/// # pub const fn as_raw(self) -> i32 { self.0 }
945/// # pub const fn from_raw(v: i32) -> Self { MainEnum(v) }
946/// # }
947/// # }
948///
949/// vk_enum_subset! {
950/// /// Doc
951/// pub enum SubsetEnum {
952/// FOO,
953/// BAR,
954/// BAZ
955/// } impl Into<vk::MainEnum>
956/// }
957/// ```
958///
959/// expands to:
960/// ```
961/// # mod vk {
962/// # #[derive(Debug, Eq, PartialEq)]
963/// # pub struct MainEnum(i32);
964/// # impl MainEnum {
965/// # pub const FOO: Self = MainEnum(0);
966/// # pub const BAR: Self = MainEnum(1);
967/// # pub const BAZ: Self = MainEnum(2);
968/// # pub const QUZ: Self = MainEnum(3);
969/// #
970/// # pub const fn as_raw(self) -> i32 { self.0 }
971/// # pub const fn from_raw(v: i32) -> Self { MainEnum(v) }
972/// # }
973/// # }
974///
975/// #[allow(non_camel_case_types)]
976/// #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
977/// #[repr(i32)]
978/// /// Doc
979/// pub enum SubsetEnum {
980/// FOO = <vk::MainEnum>::FOO.as_raw(),
981/// BAR = <vk::MainEnum>::BAR.as_raw(),
982/// BAZ = <vk::MainEnum>::BAZ.as_raw()
983/// }
984/// impl Into<vk::MainEnum> for SubsetEnum {
985/// fn into(self) -> vk::MainEnum {
986/// <vk::MainEnum>::from_raw(self as i32)
987/// }
988/// }
989/// impl std::convert::TryFrom<vk::MainEnum> for SubsetEnum {
990/// type Error = String;
991///
992/// fn try_from(value: vk::MainEnum) -> Result<Self, Self::Error> {
993/// match value {
994/// vk::MainEnum::FOO => Ok(SubsetEnum::FOO),
995/// vk::MainEnum::BAR => Ok(SubsetEnum::BAR),
996/// vk::MainEnum::BAZ => Ok(SubsetEnum::BAZ),
997/// _ => Err(
998/// format!(
999/// concat!("Cannot convert from ", stringify!(vk::MainEnum), "::{:?} to ", stringify!(SubsetEnum)),
1000/// value
1001/// )
1002/// )
1003/// }
1004/// }
1005/// }
1006/// ```
1007#[macro_export]
1008macro_rules! vk_enum_subset {
1009 (
1010 $( #[$attribute: meta] )*
1011 pub enum $name: ident {
1012 $(
1013 $( #[$variant_attribute: meta] )*
1014 $variant: ident
1015 ),+ $(,)?
1016 } impl Into<$vk_enum: ty>
1017 ) => {
1018 #[allow(non_camel_case_types)]
1019 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1020 #[repr(i32)]
1021 $( #[$attribute] )*
1022 pub enum $name {
1023 $(
1024 $( #[$variant_attribute] )*
1025 $variant = <$vk_enum>::$variant.as_raw()
1026 ),+
1027 }
1028 impl Into<$vk_enum> for $name {
1029 fn into(self) -> $vk_enum {
1030 <$vk_enum>::from_raw(self as i32)
1031 }
1032 }
1033 impl std::convert::TryFrom<$vk_enum> for $name {
1034 type Error = String;
1035
1036 fn try_from(value: $vk_enum) -> Result<Self, Self::Error> {
1037 match value {
1038 $( <$vk_enum>::$variant => Ok($name::$variant), )+
1039 _ => Err(
1040 format!(
1041 concat!("Cannot convert from ", stringify!($vk_enum), "::{:?} to ", stringify!($name)),
1042 value
1043 )
1044 )
1045 }
1046 }
1047 }
1048 }
1049}
1050
1051
1052/// Creates a chain of `std::iter::once` wrapper values.
1053///
1054/// Usage:
1055/// ```
1056/// # use vulkayes_core::iter_once_chain;
1057/// iter_once_chain!(
1058/// 1,
1059/// 2,
1060/// 3
1061/// );
1062/// ```
1063///
1064/// expands to:
1065/// ```
1066/// # use vulkayes_core::iter_once_chain;
1067/// std::iter::once(1).chain(
1068/// std::iter::once(2)
1069/// ).chain(
1070/// std::iter::once(3)
1071/// );
1072/// ```
1073#[macro_export]
1074macro_rules! iter_once_chain {
1075 (
1076 $first_value: expr
1077 $(
1078 , $rest_value: expr
1079 )*
1080 $(,)?
1081 ) => {
1082 std::iter::once($first_value)
1083 $(
1084 .chain(std::iter::once($rest_value))
1085 )*
1086 }
1087}
1088
1089/// Collect an iterator into a chosen type.
1090///
1091/// This macro is mainly provided so that collect implementation used across the crate to lower memory allocation overhead
1092/// can be swapped and benchmarked easily. Implementations may come and go and this macro will likely be completely removed at some point.
1093///
1094/// `$static_size_hint` should be a const-evaluated expression hinting how much memory to preallocate:
1095/// * For `Vec` implementation, this is ignored.
1096/// * For `smallvec` implementation, this chooses the size of the `SmallVec` stack array.
1097/// * For `reusable-memory` implementation, this chooses the size of the borrow.
1098/// * For `bumpalo` implementation, this is ignored.
1099///
1100/// `global_state_access` should be an expression:
1101/// * For `Vec` implementation, this is ignored.
1102/// * For `smallvec` implemnetation, this is ignored.
1103/// * For `reusable-memory` implementation, this provides access to the `ReusableMemory` object to borrow from.
1104/// * For `bumpalo` implementation, this provides access to `Bump` object.
1105macro_rules! collect_iter_faster {
1106 (
1107 @vec
1108 $(
1109 $iter: expr, $static_size_hint: expr
1110 ),+
1111 ) => {
1112 (
1113 $(
1114 $iter.collect::<
1115 Vec<_>
1116 >()
1117 ),+
1118 )
1119 };
1120
1121 (
1122 @smallvec
1123 $(
1124 $iter: expr, $static_size_hint: expr
1125 ),+
1126 ) => {
1127 (
1128 $(
1129 $iter.collect::<
1130 $crate::smallvec::SmallVec<
1131 [_; $static_size_hint]
1132 >
1133 >()
1134 ),+
1135 )
1136 };
1137
1138 // TODO: These are not trivial to macroize
1139 // This is tricky. The `$global_state` needs to give us the correct function to call as well such as `borrow_mut_two_as`
1140 // (
1141 // @reusable_memory $global_state_access: expr;
1142 // $(
1143 // $iter: expr, $static_size_hint: expr
1144 // ),+
1145 // ) => {
1146 // {
1147 // $global_state_access::<
1148 // $(
1149 // <$iter as Iterator>::Item
1150 // ),+
1151 // >(
1152 // [
1153 // $(
1154 // std::num::NonZeroUsize::new($static_size_hint).unwrap()
1155 // ),+
1156 // ]
1157 // )
1158 // }
1159 // };
1160 //
1161 // (
1162 // @bumpalo $global_state_access: expr;
1163 // $(
1164 // $iter: expr, $static_size_hint: expr
1165 // ),+
1166 // ) => {
1167 //
1168 // };
1169
1170 // TODO: Really need this?
1171 // (
1172 // @collected_type
1173 // ) => {
1174 //
1175 // };
1176
1177 (
1178 $(
1179 $iter: expr, $static_size_hint: expr $(, $global_state_access: expr)?
1180 ),+
1181 ) => {
1182 // TODO: Benchmark the best solution
1183 collect_iter_faster!(
1184 @vec
1185 $(
1186 $iter, $static_size_hint
1187 ),+
1188 );
1189 };
1190}
1191
1192
1193#[cfg(test)]
1194mod test {
1195 #[test]
1196 fn test_offsetable_struct() {
1197 offsetable_struct! {
1198 pub struct Foo {
1199 pub a: f32,
1200 pub b: f64,
1201 pub c: [f32; 4]
1202 } repr(C) as FooOffsets
1203 }
1204
1205 assert_eq!(Foo::offsets().a, 0);
1206 assert_eq!(Foo::offsets().b, 8);
1207 assert_eq!(Foo::offsets().c, 16);
1208 }
1209}