1#![allow(clippy::type_complexity)]
2#![allow(clippy::too_many_arguments)]
3#![doc = include_str!("../README.md")]
4#[allow(unused)]
5use bevy_ecs::{component::Component, query::QueryData, system::SystemParam};
6
7pub(crate) static TYPE_ERROR: &str = "Error: a stat does not have the appropriate type. \
8This is almost certainly a bug since we do not provide a type erased api.";
9
10#[doc(hidden)]
11pub use bevy_app::{App, Plugin};
12
13mod fraction;
14mod num_traits;
15pub use fraction::Fraction;
16pub use num_traits::{Flags, Float, Int, NumCast, Number};
17mod stream;
18pub use stream::*;
19mod querier;
20pub use querier::*;
21mod qualifier;
22pub mod types;
23pub use qualifier::{Qualifier, QualifierFlag, QualifierQuery};
24mod stat;
25#[cfg(feature = "derive")]
26pub use bevy_stat_query_derive::{Attribute, Stat};
27pub(crate) use stat::StatExt;
28pub(crate) use stat::StatInst;
29pub use stat::{Stat, StatVTable, StatValuePair};
30pub mod operations;
31pub use operations::StatValue;
32mod plugin;
33pub use plugin::{
34 GlobalStatDefaults, GlobalStatRelations, StatDeserializers, StatExtension, STAT_DESERIALIZERS,
35};
36mod stat_map;
37pub use stat_map::StatMap;
38mod buffer;
39pub mod rounding;
40use std::fmt::Debug;
41mod attribute;
42pub use attribute::Attribute;
43mod cowstr;
44
45mod sealed {
46 pub trait Sealed {}
47
48 impl<T: ?Sized> Sealed for T {}
49}
50
51pub trait Shareable: Clone + Debug + Send + Sync + 'static {}
53impl<T> Shareable for T where T: Clone + Debug + Send + Sync + 'static {}
54
55#[macro_export]
67macro_rules! vtable {
68 ($ty: ty) => {{
69 #[used]
70 static _VTABLE: $crate::StatVTable<$ty> = $crate::StatVTable::of::<$ty>();
71 &_VTABLE
72 }};
73}
74
75#[macro_export]
94macro_rules! match_stat {
95 ($stat_value: expr => {($ident: ident @ $ty: ty, $value: pat) => $expr: expr $(, $($tt: tt)*)?}) => {
96 if let Some(($ident, $value)) = $stat_value.cast::<$ty>() {
97 $expr
98 } $(
99 else {
100 $crate::match_stat!($stat_value => {$($tt)*})
101 }
102 )?
103 };
104 ($stat_value: expr => {($is: expr, $value: pat) => $expr: expr $(, $($tt: tt)*)?}) => {
105 if let Some($value) = $stat_value.is_then_cast(&$is) {
106 $expr
107 } $(
108 else {
109 $crate::match_stat!($stat_value => {$($tt)*})
110 }
111 )?
112 };
113 ($stat_value: expr => {_ => $expr: expr $(,)?}) => {
114 $expr
115 };
116 ($stat_value: expr => {}) => {()};
118}
119
120use buffer::{validate, Buffer};
121
122#[cfg(test)]
123mod test {
124 use bevy_ecs::component::Component;
125 use num_enum::{FromPrimitive, IntoPrimitive};
126 use strum::{EnumIter, IntoEnumIterator, IntoStaticStr};
127
128 use crate::{
129 stat::StatValuePair,
130 types::{StatFlags, StatIntPercentAdditive},
131 Querier, Stat, StatStream, StatValue,
132 };
133
134 #[derive(Component)]
135 pub struct X;
136
137 #[derive(Debug, Clone, Copy, IntoStaticStr, EnumIter, FromPrimitive, IntoPrimitive)]
138 #[repr(u64)]
139 pub enum IntStat {
140 #[default]
141 A,
142 B,
143 C,
144 D,
145 }
146
147 impl Stat for IntStat {
148 type Value = StatIntPercentAdditive<i32>;
149
150 fn name(&self) -> &'static str {
151 self.into()
152 }
153
154 fn vtable() -> &'static crate::StatVTable<Self> {
155 vtable!(IntStat)
156 }
157
158 fn as_index(&self) -> u64 {
159 (*self).into()
160 }
161
162 fn from_index(index: u64) -> Self {
163 index.into()
164 }
165
166 fn values() -> impl IntoIterator<Item = Self> {
167 IntStat::iter()
168 }
169 }
170
171 #[derive(Debug, Clone, Copy, IntoStaticStr, EnumIter, FromPrimitive, IntoPrimitive)]
172 #[repr(u64)]
173 pub enum FlagsStat {
174 #[default]
175 E,
176 F,
177 G,
178 H,
179 }
180
181 impl Stat for FlagsStat {
182 type Value = StatFlags<i32>;
183
184 fn name(&self) -> &'static str {
185 self.into()
186 }
187
188 fn vtable() -> &'static crate::StatVTable<Self> {
189 vtable!(FlagsStat)
190 }
191
192 fn as_index(&self) -> u64 {
193 (*self).into()
194 }
195
196 fn from_index(index: u64) -> Self {
197 index.into()
198 }
199
200 fn values() -> impl IntoIterator<Item = Self> {
201 FlagsStat::iter()
202 }
203 }
204
205 impl StatStream for X {
206 type Qualifier = u32;
207
208 fn stream_stat(
209 &self,
210 _: bevy::prelude::Entity,
211 _: &crate::QualifierQuery<Self::Qualifier>,
212 stat_value: &mut StatValuePair,
213 _: Querier<Self::Qualifier>,
214 ) {
215 match_stat! {
216 stat_value => {
217 (IntStat::A, value) => {
218 value.add(1);
219 },
220 (IntStat::B, value) => {
221 value.add(2);
222 },
223 (v @ IntStat, value) => {
224 value.add(v as i32);
225 },
226 (FlagsStat::E, value) => {
227 value.or(1);
228 },
229 (v @ FlagsStat, value) => {
230 value.or(v as i32);
231 },
232 }
233 }
234 }
235 }
236}