veloren_common_base/lib.rs
1pub mod userdata_dir;
2
3pub use userdata_dir::userdata_dir;
4
5/// Panic in debug or tests, log error/warn in release
6#[macro_export]
7macro_rules! dev_panic {
8 ($msg:expr) => {
9 if cfg!(any(debug_assertions, test)) {
10 panic!("{}", $msg);
11 } else {
12 tracing::error!("{}", $msg);
13 }
14 };
15}
16
17#[cfg(feature = "tracy")]
18pub use profiling::tracy_client;
19
20/// Allows downstream crates to conditionally do things based on whether tracy
21/// is enabled without having to expose a cargo feature themselves.
22pub const TRACY_ENABLED: bool = cfg!(feature = "tracy");
23
24#[cfg(not(feature = "tracy"))]
25#[macro_export]
26macro_rules! plot {
27 ($name:expr, $value:expr) => {
28 // type check
29 let _: f64 = $value;
30 };
31}
32
33#[cfg(feature = "tracy")]
34pub use tracy_client::plot;
35
36// https://discordapp.com/channels/676678179678715904/676685797524766720/723358438943621151
37#[cfg(not(feature = "tracy"))]
38#[macro_export]
39macro_rules! span {
40 ($guard_name:tt, $level:ident, $name:expr, $($fields:tt)*) => {
41 let span = tracing::span!(tracing::Level::$level, $name, $($fields)*);
42 let $guard_name = span.enter();
43 };
44 ($guard_name:tt, $level:ident, $name:expr) => {
45 let span = tracing::span!(tracing::Level::$level, $name);
46 let $guard_name = span.enter();
47 };
48 ($guard_name:tt, $name:expr) => {
49 let span = tracing::span!(tracing::Level::TRACE, $name);
50 let $guard_name = span.enter();
51 };
52 ($guard_name:tt, $no_tracy_name:expr, $tracy_name:expr) => {
53 $crate::span!($guard_name, $no_tracy_name);
54 };
55}
56
57#[cfg(feature = "tracy")]
58#[macro_export]
59macro_rules! span {
60 ($guard_name:tt, $level:ident, $name:expr, $($fields:tt)*) => {
61 let span = tracing::span!(tracing::Level::$level, $name, $($fields)*);
62 let $guard_name = span.enter();
63 };
64 ($guard_name:tt, $level:ident, $name:expr) => {
65 let span = tracing::span!(tracing::Level::$level, $name);
66 let $guard_name = span.enter();
67 };
68 ($guard_name:tt, $name:expr) => {
69 // Directly use `tracy_client` to decrease overhead for better timing
70 $crate::prof_span_alloc!($guard_name, $name);
71 };
72 ($guard_name:tt, $no_tracy_name:expr, $tracy_name:expr) => {
73 $crate::span!($guard_name, $tracy_name);
74 };
75}
76
77#[cfg(not(feature = "tracy"))]
78pub struct ProfSpan;
79
80/// Just implemented so that we dont need to have
81/// #[expect(clippy::drop_non_drop)] everywhere
82#[cfg(not(feature = "tracy"))]
83impl Drop for ProfSpan {
84 fn drop(&mut self) {}
85}
86
87#[cfg(feature = "tracy")]
88pub struct ProfSpan(pub tracy_client::Span);
89
90/// Like the span macro but only used when profiling and not in regular tracing
91/// operations
92#[cfg(not(feature = "tracy"))]
93#[macro_export]
94macro_rules! prof_span {
95 ($guard_name:tt, $name:expr) => {
96 let $guard_name = $crate::ProfSpan;
97 };
98 // Shorthand for when you want the guard to just be dropped at the end of the scope instead
99 // of controlling it manually
100 ($name:expr) => {
101 $crate::prof_span!(_guard, $name);
102 };
103}
104
105/// Like the span macro but only used when profiling and not in regular tracing
106/// operations
107#[cfg(feature = "tracy")]
108#[macro_export]
109macro_rules! prof_span {
110 ($guard_name:tt, $name:expr) => {
111 let $guard_name = $crate::ProfSpan(
112 // No callstack since this has significant overhead
113 $crate::tracy_client::span!($name, 0),
114 );
115 };
116 // Shorthand for when you want the guard to just be dropped at the end of the scope instead
117 // of controlling it manually
118 ($name:expr) => {
119 $crate::prof_span!(_guard, $name);
120 };
121}
122
123/// Like the prof_span macro but this one allocates so it can use strings only
124/// known at runtime.
125#[cfg(not(feature = "tracy"))]
126#[macro_export]
127macro_rules! prof_span_alloc {
128 ($guard_name:tt, $name:expr) => {
129 let $guard_name = $crate::ProfSpan;
130 };
131 // Shorthand for when you want the guard to just be dropped at the end of the scope instead
132 // of controlling it manually
133 ($name:expr) => {
134 $crate::prof_span!(_guard, $name);
135 };
136}
137
138/// Like the prof_span macro but this one allocates so it can use strings only
139/// known at runtime.
140#[cfg(feature = "tracy")]
141#[macro_export]
142macro_rules! prof_span_alloc {
143 ($guard_name:tt, $name:expr) => {
144 let $guard_name = $crate::ProfSpan({
145 struct S;
146 let type_name = core::any::type_name::<S>();
147 let function_name = &type_name[..type_name.len() - 3];
148 $crate::tracy_client::Client::running()
149 .expect("prof_span_alloc! without a running tracy_client::Client")
150 // No callstack since this has significant overhead
151 .span_alloc(Some($name), function_name, file!(), line!(), 0)
152 });
153 };
154 // Shorthand for when you want the guard to just be dropped at the end of the scope instead
155 // of controlling it manually
156 ($name:expr) => {
157 $crate::prof_span!(_guard, $name);
158 };
159}
160
161/// strum::EnumIter alternative that supports nested enums
162///
163/// Implements following items:
164/// - `NUM_KINDS` associated constant, number of defined kinds.
165/// - `iter` function, returns the iterator of all possible variants, including
166/// ones from the nested variants.
167///
168/// If you use `~const_array` prefix, you can also generate ALL constant, which
169/// has a constant array of all possible values, but only available for simple
170/// enums.
171///
172/// # Example
173/// ```rust
174/// # use veloren_common_base::enum_iter;
175/// enum_iter! {
176/// ~const_array(ALL)
177/// #[derive(Eq, PartialEq, Debug)]
178/// enum Shade {
179/// Good,
180/// Meh,
181/// Bad,
182/// }
183/// }
184///
185/// enum_iter! {
186/// #[derive(Debug, Eq, PartialEq)]
187/// #[repr(u8)]
188/// enum Color {
189/// Green = 1,
190/// Red(Shade) = 2,
191/// Blue = 3,
192/// }
193/// }
194/// assert_eq!(Shade::NUM_KINDS, 3);
195///
196/// const ALL_SHADES: [Shade; Shade::NUM_KINDS] = Shade::ALL;
197/// assert_eq!(ALL_SHADES, [Shade::Good, Shade::Meh, Shade::Bad]);
198///
199/// let results: Vec<_> = Shade::iter().collect();
200/// assert_eq!(results, vec![Shade::Good, Shade::Meh, Shade::Bad]);
201///
202/// let results: Vec<_> = Color::iter().collect();
203/// assert_eq!(results, vec![
204/// Color::Green,
205/// Color::Red(Shade::Good),
206/// Color::Red(Shade::Meh),
207/// Color::Red(Shade::Bad),
208/// Color::Blue,
209/// ]);
210/// ```
211#[macro_export]
212macro_rules! enum_iter {
213 /*
214 * Internal rule for generating ALL const array
215 */
216 // 1. Default case if you don't have any nested nums
217 (@all_array_impl,
218 $vis:vis,
219 ~const_array($all_array:ident)
220 $($variant:ident)*
221 ) => {
222 #[allow(dead_code)]
223 /// Contains all possible values this enum can have
224 $vis const $all_array: [Self; Self::NUM_KINDS] = [$(
225 Self::$variant,
226 )*];
227 };
228 // 2. Case with nested_enums
229 (@all_array_impl,
230 $vis:vis,
231 ~const_array($all_array:ident)
232 $($variant:ident $((
233 $nested_enum:ty
234 ))?)*
235 ) => {
236 compile_error!(
237 "can't use ~const_array with an enum that contains nested enums"
238 );
239 };
240 // 3. no ~const_array
241 (@all_array_impl,
242 $vis:vis,
243 $($variant:ident $((
244 $nested_enum:ty
245 ))?)*
246 ) => {};
247 /*
248 * Internal rule to add a variant to the iterable buffer
249 */
250 // 1. If having a nested enum, use `extend` with nested iterator
251 (@add_variant_impl, $buff:ident, $variant:ident $nested_enum:ty) => {
252 $buff.extend(
253 <$nested_enum>::iter().map(Self::$variant)
254 );
255 };
256 // 2. If having a trivial enum, use `push`
257 (@add_variant_impl, $buff:ident, $variant:ident) => {
258 $buff.push(Self::$variant);
259 };
260 /*
261 * Entrypoint, returns a passed `enum` and implements all the things
262 */
263 (
264 $(~const_array($all_array:ident))?
265 $( #[ $enum_attr:meta ] )*
266 $vis:vis enum $enum_name:ident {
267 $(
268 $( #[ $variant_attr:meta ] )*
269 $variant:ident $(($nested_enum:ty))? $(= $idx:literal)?
270 ),* $(,)?
271 }
272 ) => {
273 $( #[ $enum_attr ] )*
274 $vis enum $enum_name {
275 $(
276 $( #[ $variant_attr ] )*
277 $variant $(($nested_enum))? $(= $idx)?
278 ),*
279 }
280
281 impl $enum_name {
282 // repeated macro to construct 0 + (1 + 1 + 1) per each field
283 #[allow(dead_code)]
284 /// Number of "kinds" this enum has
285 $vis const NUM_KINDS: usize = 0 $(+ {
286 // fake capture
287 #[allow(non_snake_case, unused_variables)]
288 let $variant = 0;
289 1
290 })*;
291
292 $crate::enum_iter!(@all_array_impl,
293 $vis,
294 $(~const_array($all_array))?
295 $($variant $(($nested_enum))?)*
296 );
297
298 // Generates a vector of all possible variants, including nested
299 // ones so we can then use it for `iter`
300 fn all_variants() -> Vec<$enum_name> {
301 #![allow(clippy::vec_init_then_push)]
302
303 let mut buff = vec![];
304 $(
305 $crate::enum_iter!(@add_variant_impl,
306 buff,
307 $variant $($nested_enum)?
308 );
309 )*
310
311 buff
312 }
313
314 /// Iterates over all possible variants, including nested ones.
315 $vis fn iter() -> impl Iterator<Item=Self> {
316 Self::all_variants().into_iter()
317 }
318 }
319 }
320}
321
322#[test]
323fn test_enum_iter() {
324 enum_iter! {
325 ~const_array(ALL)
326 #[derive(Eq, PartialEq, Debug)]
327 enum Shade {
328 Good,
329 Meh,
330 Bad,
331 }
332 }
333
334 enum_iter! {
335 #[derive(Debug, Eq, PartialEq)]
336 #[repr(u8)]
337 enum Color {
338 Green = 1,
339 // RemovedVariant = 2
340 Red(Shade) = 3,
341 Blue = 4,
342 }
343 }
344
345 assert_eq!(Shade::NUM_KINDS, 3);
346 const ALL_SHADES: [Shade; Shade::NUM_KINDS] = Shade::ALL;
347 assert_eq!(ALL_SHADES, [Shade::Good, Shade::Meh, Shade::Bad]);
348
349 let results: Vec<_> = Shade::iter().collect();
350 assert_eq!(results, vec![Shade::Good, Shade::Meh, Shade::Bad]);
351
352 let results: Vec<_> = Color::iter().collect();
353 assert_eq!(results, vec![
354 Color::Green,
355 Color::Red(Shade::Good),
356 Color::Red(Shade::Meh),
357 Color::Red(Shade::Bad),
358 Color::Blue,
359 ]);
360
361 let discriminant = |color: &Color| -> u8 {
362 // SAFETY: copied from docs on std::mem::discriminant
363 //
364 // As Color is marked with repr(u8), its layout is defined as union
365 // of structs and every one of them has as its first field the tag
366 // that is u8
367 //
368 // More on that here:
369 // https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-field-less-enums
370 unsafe { *<*const _>::from(color).cast::<u8>() }
371 };
372 let results = [
373 Color::Green,
374 Color::Red(Shade::Good),
375 Color::Red(Shade::Meh),
376 Color::Red(Shade::Bad),
377 Color::Blue,
378 ]
379 .iter()
380 .map(discriminant)
381 .collect::<Vec<_>>();
382
383 assert_eq!(results, vec![
384 1, // Green = 1
385 3, // Red(Shade) = 3
386 3, // Red(Shade) = 3
387 3, // Red(Shade) = 3
388 4, // Blue = 4
389 ]);
390}
391
392/// Implements the `iter` function, which returns an iterator over all possible
393/// combinations of the struct's fields, assuming each field's type implements
394/// the `iter` function itself.
395///
396/// # Example
397///
398/// ```rust
399/// # use veloren_common_base::struct_iter;
400/// # use veloren_common_base::enum_iter;
401///
402/// enum_iter! {
403/// #[derive(Eq, PartialEq, Debug, Clone)]
404/// enum Species {
405/// BlueDragon,
406/// RedDragon,
407/// }
408/// }
409///
410/// enum_iter! {
411/// #[derive(Eq, PartialEq, Debug, Clone)]
412/// enum BodyType {
413/// Male,
414/// Female,
415/// }
416/// }
417///
418/// struct_iter! {
419/// #[derive(Eq, PartialEq, Debug)]
420/// struct Body {
421/// species: Species,
422/// body_type: BodyType,
423/// }
424/// }
425///
426/// let results: Vec<_> = Body::iter().collect();
427/// assert_eq!(results, vec![
428/// Body {
429/// species: Species::BlueDragon,
430/// body_type: BodyType::Male
431/// },
432/// Body {
433/// species: Species::BlueDragon,
434/// body_type: BodyType::Female
435/// },
436/// Body {
437/// species: Species::RedDragon,
438/// body_type: BodyType::Male
439/// },
440/// Body {
441/// species: Species::RedDragon,
442/// body_type: BodyType::Female
443/// },
444/// ])
445/// ```
446#[macro_export]
447macro_rules! struct_iter {
448 (
449 $( #[ $type_attr:meta ] )*
450 $vis:vis struct $struct_name:ident {
451 $(
452 $( #[ $field_attr:meta ] )*
453 $field_vis:vis $field:ident: $field_type:ty
454 ),* $(,)?
455 }
456 ) => {
457 $( #[ $type_attr ] )*
458 $vis struct $struct_name {
459 $(
460 $( #[ $field_attr ] )*
461 $field_vis $field: $field_type
462 ),*
463 }
464
465 impl $struct_name {
466 // Generate a vector of all possible combinations so that
467 // we can then use it in `iter`
468 fn all_variants() -> Vec<$struct_name> {
469 #[derive(Default, Clone)]
470 pub struct Builder {
471 $(
472 $( #[ $field_attr ] )*
473 $field: Option<$field_type>
474 ),*
475 }
476
477 impl Builder {
478 $(
479 pub fn $field(mut self, val: $field_type) -> Self {
480 self.$field = Some(val);
481 self
482 }
483 )*
484
485 pub fn build_expect(self) -> $struct_name {
486 $struct_name {
487 $(
488 $field: self.$field.unwrap()
489 ),*
490 }
491 }
492 }
493
494 let mut builder_buff = vec![Builder::default()];
495 // launch build spiral
496 $(
497 let mut next_buff = vec![];
498 for step in builder_buff {
499 for kind in <$field_type>::iter() {
500 next_buff.push(step.clone().$field(kind));
501 }
502 }
503 builder_buff = next_buff;
504 )*
505
506 let mut result_buff = vec![];
507 for builder in builder_buff {
508 result_buff.push(builder.build_expect())
509 }
510 return result_buff;
511 }
512
513 /// Iterates over all possible combinations
514 $vis fn iter() -> impl Iterator<Item=Self> {
515 Self::all_variants().into_iter()
516 }
517 }
518 }
519}
520
521#[test]
522fn test_struct_iter() {
523 enum_iter! {
524 #[derive(Eq, PartialEq, Debug, Clone)]
525 enum Species {
526 BlueDragon,
527 RedDragon,
528 }
529 }
530
531 enum_iter! {
532 #[derive(Eq, PartialEq, Debug, Clone)]
533 enum BodyType {
534 Male,
535 Female,
536 }
537 }
538
539 struct_iter! {
540 #[derive(Eq, PartialEq, Debug)]
541 struct Body {
542 species: Species,
543 body_type: BodyType,
544 }
545 }
546
547 let results: Vec<_> = Body::iter().collect();
548 assert_eq!(results, vec![
549 Body {
550 species: Species::BlueDragon,
551 body_type: BodyType::Male
552 },
553 Body {
554 species: Species::BlueDragon,
555 body_type: BodyType::Female
556 },
557 Body {
558 species: Species::RedDragon,
559 body_type: BodyType::Male
560 },
561 Body {
562 species: Species::RedDragon,
563 body_type: BodyType::Female
564 },
565 ])
566}