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}