1use std::fmt::Debug;
2
3use crate::attribute::Attribute;
4use crate::plugin::GlobalStatRelations;
5use crate::stat::StatExt;
6use crate::{
7 plugin::GlobalStatDefaults, Buffer, QualifierFlag, QualifierQuery, Stat, StatInst, StatStream,
8};
9use crate::{validate, StatValue, StatValuePair};
10use bevy_ecs::reflect::ReflectComponent;
11use bevy_ecs::{
12 component::Component,
13 entity::Entity,
14 query::With,
15 system::{Query, Res, SystemParam},
16};
17use bevy_reflect::Reflect;
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Component, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Reflect)]
22#[reflect(Component)]
23pub struct StatEntity;
24
25#[derive(Debug, SystemParam)]
29pub struct StatEntities<'w, 's, Q: QualifierFlag> {
30 defaults: Option<Res<'w, GlobalStatDefaults>>,
31 relations: Option<Res<'w, GlobalStatRelations<Q>>>,
32 entities: Query<'w, 's, Entity, With<StatEntity>>,
33}
34
35impl<'w, 's, Q: QualifierFlag> StatEntities<'w, 's, Q> {
36 pub fn join<'t, S: StatStream<Qualifier = Q>>(
37 &'t self,
38 stream: S,
39 ) -> JoinedQuerier<'w, 's, 't, Q, S> {
40 JoinedQuerier { base: self, stream }
41 }
42}
43
44pub struct JoinedQuerier<'w, 's, 't, Q: QualifierFlag, S: StatStream<Qualifier = Q>> {
45 base: &'t StatEntities<'w, 's, Q>,
46 stream: S,
47}
48
49impl<'w, 's, 't, Q: QualifierFlag, S: StatStream<Qualifier = Q>> JoinedQuerier<'w, 's, 't, Q, S> {
50 pub fn join<T: StatStream<Qualifier = Q>>(
51 self,
52 stream: T,
53 ) -> JoinedQuerier<'w, 's, 't, Q, (S, T)> {
54 JoinedQuerier {
55 base: self.base,
56 stream: (self.stream, stream),
57 }
58 }
59
60 pub fn query_stat<T: Stat>(
61 &self,
62 entity: Entity,
63 qualifier: &QualifierQuery<Q>,
64 stat: &T,
65 ) -> Option<T::Value> {
66 self.query_stat_erased(entity, qualifier, stat.as_entry())
67 .map(|x| unsafe { x.into() })
68 }
69
70 pub fn query_relation<T: Stat>(
71 &self,
72 from: Entity,
73 to: Entity,
74 qualifier: &QualifierQuery<Q>,
75 stat: &T,
76 ) -> Option<T::Value> {
77 self.query_relation_erased(from, to, qualifier, stat.as_entry())
78 .map(|x| unsafe { x.into() })
79 }
80
81 pub fn eval_stat<T: Stat>(
82 &self,
83 entity: Entity,
84 qualifier: &QualifierQuery<Q>,
85 stat: &T,
86 ) -> Option<<T::Value as StatValue>::Out> {
87 self.query_stat(entity, qualifier, stat).map(|x| x.eval())
88 }
89
90 pub fn eval_relation<T: Stat>(
91 &self,
92 from: Entity,
93 to: Entity,
94 qualifier: &QualifierQuery<Q>,
95 stat: &T,
96 ) -> Option<<T::Value as StatValue>::Out> {
97 self.query_relation(from, to, qualifier, stat)
98 .map(|x| x.eval())
99 }
100
101 pub fn has_attribute<'a>(&self, entity: Entity, attribute: impl Into<Attribute<'a>>) -> bool {
102 self.has_attribute_erased(entity, attribute.into())
103 }
104}
105
106impl<Q: QualifierFlag, S: StatStream<Qualifier = Q>> ErasedQuerier<Q>
107 for JoinedQuerier<'_, '_, '_, Q, S>
108{
109 fn query_stat_erased(
110 &self,
111 entity: Entity,
112 query: &QualifierQuery<Q>,
113 stat: StatInst,
114 ) -> Option<Buffer> {
115 let value = if let Some(defaults) = &self.base.defaults {
116 defaults.get_dyn(stat)
117 } else {
118 (stat.vtable.default)()
119 };
120 let mut pair = StatValuePair { stat, value };
121 if let Some(relations) = &self.base.relations {
122 relations.stream_stat(entity, query, &mut pair, Querier(self));
123 }
124 self.stream
125 .stream_stat(entity, query, &mut pair, Querier(self));
126 Some(pair.value)
127 }
128
129 fn query_relation_erased(
130 &self,
131 from: Entity,
132 to: Entity,
133 query: &QualifierQuery<Q>,
134 stat: StatInst,
135 ) -> Option<Buffer> {
136 let value = if let Some(defaults) = &self.base.defaults {
137 defaults.get_dyn(stat)
138 } else {
139 (stat.vtable.default)()
140 };
141 let mut pair = StatValuePair { stat, value };
142 self.stream
143 .stream_relation(&self.stream, from, to, query, &mut pair, Querier(self));
144 Some(pair.value)
145 }
146
147 fn has_attribute_erased(&self, entity: Entity, attribute: Attribute) -> bool {
148 self.stream.has_attribute(entity, attribute)
149 }
150}
151
152trait ErasedQuerier<Q: QualifierFlag> {
156 fn query_stat_erased(
158 &self,
159 entity: Entity,
160 query: &QualifierQuery<Q>,
161 stat: StatInst,
162 ) -> Option<Buffer>;
163
164 fn query_relation_erased(
166 &self,
167 from: Entity,
168 to: Entity,
169 query: &QualifierQuery<Q>,
170 stat: StatInst,
171 ) -> Option<Buffer>;
172
173 fn has_attribute_erased(&self, entity: Entity, attribute: Attribute) -> bool;
175}
176
177pub struct Querier<'t, Q: QualifierFlag>(&'t dyn ErasedQuerier<Q>);
179
180impl<Q: QualifierFlag> Clone for Querier<'_, Q> {
181 fn clone(&self) -> Self {
182 *self
183 }
184}
185
186impl<Q: QualifierFlag> Copy for Querier<'_, Q> {}
187
188impl<Q: QualifierFlag> Debug for Querier<'_, Q> {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 f.debug_struct("Querier").finish_non_exhaustive()
191 }
192}
193
194impl<Q: QualifierFlag> Querier<'_, Q> {
195 pub fn noop() -> Querier<'static, Q> {
197 static _Q: NoopQuerier = NoopQuerier;
198 Querier(&_Q)
199 }
200
201 pub fn query_stat<S: Stat>(
203 &self,
204 entity: Entity,
205 qualifier: &QualifierQuery<Q>,
206 stat: &S,
207 ) -> Option<S::Value> {
208 validate::<S::Value>();
209 self.0
210 .query_stat_erased(entity, qualifier, stat.as_entry())
211 .map(|x| unsafe { x.into() })
212 }
213
214 pub fn query_relation<S: Stat>(
216 &self,
217 from: Entity,
218 to: Entity,
219 qualifier: &QualifierQuery<Q>,
220 stat: &S,
221 ) -> Option<S::Value> {
222 validate::<S::Value>();
223 self.0
224 .query_relation_erased(from, to, qualifier, stat.as_entry())
225 .map(|x| unsafe { x.into() })
226 }
227
228 pub fn eval_stat<S: Stat>(
230 &self,
231 entity: Entity,
232 qualifier: &QualifierQuery<Q>,
233 stat: &S,
234 ) -> Option<<S::Value as StatValue>::Out> {
235 validate::<S::Value>();
236 self.query_stat(entity, qualifier, stat)
237 .map(|x| StatValue::eval(&x))
238 }
239
240 pub fn eval_relation<S: Stat>(
242 &self,
243 from: Entity,
244 to: Entity,
245 qualifier: &QualifierQuery<Q>,
246 stat: &S,
247 ) -> Option<<S::Value as StatValue>::Out> {
248 validate::<S::Value>();
249 self.query_relation(from, to, qualifier, stat)
250 .map(|x| StatValue::eval(&x))
251 }
252
253 pub fn has_attribute<'a>(&self, entity: Entity, attribute: impl Into<Attribute<'a>>) -> bool {
255 self.0.has_attribute_erased(entity, attribute.into())
256 }
257}
258
259pub struct NoopQuerier;
261
262impl<Q: QualifierFlag> ErasedQuerier<Q> for NoopQuerier {
263 fn query_relation_erased(
264 &self,
265 _: Entity,
266 _: Entity,
267 _: &QualifierQuery<Q>,
268 _: StatInst,
269 ) -> Option<Buffer> {
270 None
271 }
272
273 fn query_stat_erased(&self, _: Entity, _: &QualifierQuery<Q>, _: StatInst) -> Option<Buffer> {
274 None
275 }
276
277 fn has_attribute_erased(&self, _: Entity, _: Attribute) -> bool {
278 false
279 }
280}