1use std::any::TypeId;
4
5use bevy_ecs::{change_detection::DetectChanges, prelude::Resource, world::Ref};
6use bevy_reflect::{FromType, PartialReflect, Reflect};
7
8use crate::{CVarError, CVarFlags};
9
10pub trait CVarMeta:
12 Resource + std::ops::Deref<Target = Self::Inner> + std::ops::DerefMut<Target = Self::Inner>
13{
14 type Inner: std::fmt::Debug + PartialReflect;
16 const CVAR_PATH: &'static str;
18 fn flags() -> CVarFlags;
20 fn default_inner() -> Self::Inner;
22 fn set_to_default(&mut self);
25}
26
27#[derive(Clone)]
29pub struct ReflectCVar {
30 reflect_inner: for<'a> fn(&'a dyn PartialReflect) -> Result<&'a dyn PartialReflect, CVarError>,
31 reflect_inner_mut:
32 for<'a> fn(&'a mut dyn PartialReflect) -> Result<&'a mut dyn PartialReflect, CVarError>,
33 default_inner: fn() -> Box<dyn PartialReflect>,
34 is_default_value: fn(Ref<dyn PartialReflect>) -> bool,
35 inner_type: TypeId,
36 path: &'static str,
37 flags: CVarFlags,
38}
39
40impl ReflectCVar {
41 pub fn inner_type(&self) -> TypeId {
43 self.inner_type
44 }
45
46 pub fn cvar_path(&self) -> &'static str {
48 self.path
49 }
50
51 pub fn flags(&self) -> CVarFlags {
53 self.flags
54 }
55
56 pub fn reflect_inner<'a>(
58 &self,
59 cvar: &'a dyn PartialReflect,
60 ) -> Result<&'a dyn PartialReflect, CVarError> {
61 (self.reflect_inner)(cvar)
62 }
63
64 pub fn reflect_inner_mut<'a>(
66 &self,
67 cvar: &'a mut dyn PartialReflect,
68 ) -> Result<&'a mut dyn PartialReflect, CVarError> {
69 (self.reflect_inner_mut)(cvar)
70 }
71
72 pub fn reflect_apply(
74 &self,
75 cvar: &mut dyn PartialReflect,
76 value: &dyn PartialReflect,
77 ) -> Result<(), CVarError> {
78 let inner_mut = self.reflect_inner_mut(cvar)?;
79
80 inner_mut.try_apply(value)?;
81 Ok(())
82 }
83
84 pub fn default_inner(&self) -> Box<dyn PartialReflect> {
86 (self.default_inner)()
87 }
88
89 pub fn is_default_value<T: Reflect + ?Sized>(&self, r: Ref<T>) -> bool {
91 (self.is_default_value)(r.map(|x| x.as_partial_reflect()))
92 }
93}
94
95impl<T: CVarMeta> FromType<T> for ReflectCVar {
96 fn from_type() -> Self {
97 ReflectCVar {
98 inner_type: std::any::TypeId::of::<T::Inner>(),
99 reflect_inner: |r| {
101 r.reflect_ref()
102 .as_tuple_struct()
103 .map_err(|_| CVarError::BadCVarType)?
104 .field(0)
105 .ok_or(CVarError::BadCVarType)
106 },
107
108 reflect_inner_mut: |r| {
109 r.reflect_mut()
110 .as_tuple_struct()
111 .map_err(|_| CVarError::BadCVarType)?
112 .field_mut(0)
113 .ok_or(CVarError::BadCVarType)
114 },
115 default_inner: || Box::new(T::default_inner()),
116 is_default_value: |r| r.added() == r.last_changed(),
117 path: T::CVAR_PATH,
118 flags: T::flags(),
119 }
120 }
121}