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}