vulkayes_core/util/
fmt.rs

1use std::fmt::{Debug, Display, Formatter, Result};
2
3#[macro_export]
4macro_rules! log_trace_common {
5	(
6		$title: literal,
7		$(
8			$log_item: expr
9		),*
10	) => {
11		log_trace_common!(
12			trace;
13			$title,
14			$(
15				$log_item
16			),*
17		)
18	};
19
20	(
21		$not_trace: ident;
22		$title: literal,
23		$(
24			$log_item: expr
25		),*
26	) => {
27		log::$not_trace!(
28			concat!(
29				$title,
30				$(
31					concat!("\n\t", stringify!($log_item), " = ", "{:?}")
32				),*
33			),
34			$(
35				$log_item
36			),*
37		)
38	};
39}
40
41
42/// ```
43/// # use vulkayes_core::debugize_struct;
44/// # use std::ptr::null;
45/// # #[derive(Debug)]
46/// # struct TesterInnerFoo { foo: usize }
47/// # struct TesterInnerBar { p_bar: *const usize }
48/// # struct TesterInnerBaz { p_baz: *const usize, baz_size: u32 }
49/// # struct Tester { foo: usize, p_bar: *const usize, p_baz: *const usize, baz_size: u32, foo_r: TesterInnerFoo, p_bar_r: *const TesterInnerBar, p_baz_r: *const TesterInnerBaz, baz_r_size: usize, n_qux: usize }
50/// # let create_info = Tester { foo: 1, p_bar: null(), p_baz: null(), baz_size: 0, foo_r: TesterInnerFoo { foo: 2 }, p_bar_r: null(), p_baz_r: null(), baz_r_size: 0, n_qux: 3 };
51///
52/// let debuggable_value = unsafe {
53/// 	debugize_struct!(
54/// 		create_info;
55/// 		{
56/// 			// Simple alias
57/// 			foo: foo; // => create_info.foo
58/// 			// Depointerization
59/// 			bar: *p_bar; // => create_info.p_bar.as_ref()
60/// 			// Slice depointerization - unsafe
61/// 			baz: *[baz_size] p_baz; // => create_info.p_baz.as_ref().map(|r| std::slice::from_raw_parts(r, create_info.baz_size))
62/// 			// Recursion
63/// 			foo_r: { foo: foo; } from foo_r;
64/// 			bar_r: { bar: *p_bar; } from *p_bar_r;
65/// 			baz_r: { baz: *[baz_size] p_baz; } from *[baz_r_size] p_baz_r;
66/// 			// Custom closure
67/// 			qux: n_qux | { n_qux + 1 }; // (|n_qux| { n_qux + 1 })(create_info.n_qux)
68/// 		}
69/// 	)
70/// };
71///
72/// dbg!(debuggable_value);
73/// ```
74#[macro_export]
75macro_rules! debugize_struct {
76	(
77		$input: expr;
78		{
79			$(
80				$field: ident: $({ $($recursion: tt)+ } from)? $(* $([$size_target: ident])? )? $target: ident $(| { $($closure: tt)+ })?;
81			)+
82		}
83	) => {
84		{
85			#[allow(non_camel_case_types)]
86			struct Debugizer<$($field),+> {
87				$($field: $field),+
88			}
89			#[allow(non_camel_case_types)]
90			impl<$($field: std::fmt::Debug),+> std::fmt::Debug for Debugizer<$($field),+> {
91				fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92					f.debug_struct("")
93					$(
94						.field(stringify!($field), &self.$field)
95					)+
96					.finish()
97				}
98			}
99
100			Debugizer {
101				$(
102					$field: $crate::debugize_struct!(
103						$input;
104						: $({ $($recursion)+ } from)? $(* $([$size_target])? )? $target $(| { $($closure)+ } )?
105					)
106				),+
107			}
108		}
109	};
110
111	// Recursion
112	(
113		$input: expr;
114		: { $($recursion: tt)+ } from $target: ident
115	) => {
116		$crate::debugize_struct!(
117			$input.$target;
118			{
119				$($recursion)+
120			}
121		)
122	};
123
124	(
125		$input: expr;
126		: { $($recursion: tt)+ } from *$target: ident
127	) => {
128		$crate::debugize_struct!($input; : *$target).map(
129			|r| {
130				$crate::debugize_struct!(
131					r;
132					{
133						$($recursion)+
134					}
135				)
136			}
137		)
138	};
139
140	(
141		$input: expr;
142		: { $($recursion: tt)+ } from *[$size_target: ident] $target: ident
143	) => {
144		$crate::debugize_struct!($input; : *[$size_target] $target).map(
145			|s| s.iter().map(|e| {
146					$crate::debugize_struct!(
147						e;
148						{
149							$($recursion)+
150						}
151					)
152				}
153			).collect::<Vec<_>>()
154		)
155	};
156
157	// Custom closure
158	(
159		$input: expr;
160		: $target: ident | { $($closure: tt)+ }
161	) => {
162		(|$target| { $($closure)+ })($input.$target)
163	};
164
165	// Slice depointerization
166	(
167		$input: expr;
168		: *[$size_target: ident] $target: ident
169	) => {
170		$input.$target.as_ref().map(|r| std::slice::from_raw_parts(r, $input.$size_target as usize))
171	};
172
173	// Depointerization
174	(
175		$input: expr;
176		: *$target: ident
177	) => {
178		$input.$target.as_ref()
179	};
180
181	// Simple alias
182	(
183		$input: expr;
184		: $target: ident
185	) => {
186		$input.$target
187	};
188}
189
190pub fn log_vulkayes_debug_info() {
191	log::debug!(
192		"Enabled features:
193	host_allocator: {}
194	rust_host_allocator: {}
195	naive_device_allocator: {}
196	multi_thread: {}
197	insecure_hash: {}
198	runtime_implicit_validations: {}
199	vulkan1_1: {}
200	vulkan1_2: {}
201",
202		cfg!(feature = "host_allocator"),
203		cfg!(feature = "rust_host_allocator"),
204		cfg!(feature = "naive_device_allocator"),
205		cfg!(feature = "multi_thread"),
206		cfg!(feature = "insecure_hash"),
207		cfg!(feature = "runtime_implicit_validations"),
208		cfg!(feature = "vulkan1_1"),
209		cfg!(feature = "vulkan1_2"),
210	);
211}
212
213/// Formats Vulkan handle as `<ObjectType $raw>`.
214pub fn format_handle<H: ash::vk::Handle>(handle: H) -> impl Debug + Display {
215	struct Inner {
216		ty: ash::vk::ObjectType,
217		raw: u64
218	}
219	impl Debug for Inner {
220		fn fmt(&self, f: &mut Formatter) -> Result {
221			write!(f, "<{:?} 0x{:x}>", self.ty, self.raw)
222		}
223	}
224	impl Display for Inner {
225		fn fmt(&self, f: &mut Formatter) -> Result {
226			write!(f, "<{:?} 0x{:x}>", self.ty, self.raw)
227		}
228	}
229
230	Inner {
231		ty: H::TYPE,
232		raw: handle.as_raw()
233	}
234}
235
236#[repr(transparent)]
237#[derive(Clone, Copy, Default)]
238pub struct VkVersion(pub u32);
239impl VkVersion {
240	pub fn new(major: u32, minor: u32, patch: u32) -> Self {
241		VkVersion(ash::vk::make_version(major, minor, patch))
242	}
243}
244impl Debug for VkVersion {
245	fn fmt(&self, f: &mut Formatter) -> Result {
246		<VkVersion as Display>::fmt(self, f)
247	}
248}
249impl Display for VkVersion {
250	fn fmt(&self, f: &mut Formatter) -> Result {
251		write!(
252			f,
253			"v{}.{}.{}",
254			ash::vk::version_major(self.0),
255			ash::vk::version_minor(self.0),
256			ash::vk::version_patch(self.0)
257		)
258	}
259}
260impl From<u32> for VkVersion {
261	fn from(v: u32) -> Self {
262		VkVersion(v)
263	}
264}
265
266/// Formats `[u8; 16]` as canonical `xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx`.
267pub fn format_uuid(uuid: [u8; 16]) -> impl Debug + Display {
268	struct Inner {
269		uuid: [u8; 16]
270	}
271	impl Debug for Inner {
272		fn fmt(&self, f: &mut Formatter) -> Result {
273			write!(
274				f,
275				"{:0>2x}{:0>2x}{:0>2x}{:0>2x}-{:0>2x}{:0>2x}-{:0>2x}{:0>2x}-{:0>2x}{:0>2x}-{:0>2x}{:0>2x}{:0>2x}{:0>2x}{:0>2x}{:0>2x}",
276				self.uuid[0], self.uuid[1], self.uuid[2], self.uuid[3],
277				self.uuid[4], self.uuid[5],
278				self.uuid[6], self.uuid[7],
279				self.uuid[8], self.uuid[9],
280				self.uuid[10], self.uuid[11], self.uuid[12], self.uuid[13], self.uuid[14], self.uuid[15]
281			)
282		}
283	}
284	impl Display for Inner {
285		fn fmt(&self, f: &mut Formatter) -> Result {
286			write!(
287				f,
288				"{:x}{:x}{:x}{:x}-{:x}{:x}-{:x}{:X}-{:x}{:x}-{:x}{:x}{:x}{:x}{:x}{:x}",
289				self.uuid[0],
290				self.uuid[1],
291				self.uuid[2],
292				self.uuid[3],
293				self.uuid[4],
294				self.uuid[5],
295				self.uuid[6],
296				self.uuid[7],
297				self.uuid[8],
298				self.uuid[9],
299				self.uuid[10],
300				self.uuid[11],
301				self.uuid[12],
302				self.uuid[13],
303				self.uuid[14],
304				self.uuid[15]
305			)
306		}
307	}
308
309	Inner { uuid }
310}