ambient_ecs/
component.rs

1use core::fmt;
2use std::{
3    any::{Any, TypeId},
4    cmp::Ordering,
5    fmt::Debug,
6    marker::PhantomData,
7};
8
9use downcast_rs::Downcast;
10use parking_lot::MappedRwLockReadGuard;
11use serde::{
12    self,
13    de::{self, DeserializeSeed},
14    Deserialize, Serialize,
15};
16
17use crate::{
18    component_traits::IComponentBuffer, with_component_registry, AttributeGuard, AttributeStoreGuard, AttributeStoreGuardMut,
19    ComponentAttribute, ComponentEntry, ComponentPath, ComponentVTable, Debuggable, Description, Name, Serializable,
20};
21
22pub trait ComponentValueBase: Send + Sync + Downcast + 'static {
23    fn type_name(&self) -> &'static str {
24        std::any::type_name::<Self>()
25    }
26}
27
28impl<T: Send + Sync + 'static> ComponentValueBase for T {}
29pub trait ComponentValue: ComponentValueBase + Clone {}
30impl<T: ComponentValueBase + Clone> ComponentValue for T {}
31
32/// Component key
33pub struct Component<T: 'static> {
34    desc: ComponentDesc,
35    _marker: PhantomData<T>,
36}
37
38impl<T: 'static> From<ComponentDesc> for Component<T> {
39    fn from(value: ComponentDesc) -> Self {
40        Self::new(value)
41    }
42}
43
44impl<T: 'static> From<Component<T>> for ComponentDesc {
45    #[inline]
46    fn from(value: Component<T>) -> Self {
47        value.desc
48    }
49}
50
51impl<T: 'static> std::ops::Deref for Component<T> {
52    type Target = ComponentDesc;
53
54    #[inline]
55    fn deref(&self) -> &Self::Target {
56        &self.desc
57    }
58}
59
60impl<T> Debug for Component<T> {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        f.debug_struct("Component").field("path", &self.path()).field("index", &self.desc.index).finish()
63    }
64}
65
66impl Debug for ComponentDesc {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.debug_struct("ComponentDesc").field("path", &self.path()).field("index", &self.index).finish_non_exhaustive()
69    }
70}
71
72impl<T: 'static> Component<T> {
73    /// Returns an untyped description of the component key
74    #[inline]
75    pub fn desc(&self) -> ComponentDesc {
76        self.desc
77    }
78}
79
80impl<T> Clone for Component<T> {
81    fn clone(&self) -> Self {
82        Self { desc: self.desc, _marker: PhantomData }
83    }
84}
85
86impl<T> Copy for Component<T> {}
87
88impl<T> PartialEq for Component<T> {
89    fn eq(&self, other: &Self) -> bool {
90        self.desc.index == other.index
91    }
92}
93
94impl<T> Eq for Component<T> {}
95
96impl<T> PartialEq<ComponentDesc> for Component<T> {
97    fn eq(&self, other: &ComponentDesc) -> bool {
98        self.desc.index == other.index
99    }
100}
101
102impl<T> PartialEq<Component<T>> for ComponentDesc {
103    fn eq(&self, other: &Component<T>) -> bool {
104        self.index == other.desc.index
105    }
106}
107
108impl<T> PartialOrd for Component<T> {
109    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
110        self.desc.index.partial_cmp(&other.desc.index)
111    }
112}
113
114impl<T> Ord for Component<T> {
115    fn cmp(&self, other: &Self) -> Ordering {
116        self.desc.index.cmp(&other.desc.index)
117    }
118}
119
120impl<T: ComponentValue> std::hash::Hash for Component<T> {
121    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
122        self.index().hash(state);
123    }
124}
125
126impl<T> Component<T> {
127    /// Create a component key from the untyped description
128    /// # Panics
129    ///
130    /// If the types do not match
131    pub fn new(desc: ComponentDesc) -> Self {
132        if !desc.is::<T>() {
133            panic!(
134                "Attempt to convert component description of {:?} into component of type {:?}",
135                desc.type_name(),
136                std::any::type_name::<T>()
137            );
138        }
139        Self { desc, _marker: PhantomData }
140    }
141
142    pub fn as_debug<'a>(&self, value: &'a T) -> &'a dyn Debug {
143        self.desc.as_debug(value)
144    }
145}
146
147/// Contains enough information to construct, erase, and de-erase a component key.
148#[repr(C)]
149#[derive(Clone, Copy)]
150pub struct ComponentDesc {
151    index: u32,
152    pub(crate) vtable: &'static ComponentVTable<()>,
153}
154
155impl Eq for ComponentDesc {}
156
157impl std::hash::Hash for ComponentDesc {
158    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159        self.index.hash(state);
160    }
161}
162
163impl PartialEq for ComponentDesc {
164    fn eq(&self, other: &Self) -> bool {
165        self.index == other.index
166    }
167}
168
169impl PartialOrd for ComponentDesc {
170    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171        self.index.partial_cmp(&other.index)
172    }
173}
174impl Ord for ComponentDesc {
175    fn cmp(&self, other: &Self) -> Ordering {
176        self.index.cmp(&other.index)
177    }
178}
179
180impl ComponentDesc {
181    /// The fully qualified component path.
182    pub fn path(&self) -> String {
183        if let Some(path) = self.vtable.path {
184            path.to_string()
185        } else {
186            self.attribute::<ComponentPath>().expect("No path for component").0.clone()
187        }
188    }
189
190    /// The last segment of the component path. Do not use this as a unique identifier; use [Self::path] instead.
191    pub fn path_last(&self) -> String {
192        if let Some(path) = self.vtable.path {
193            path.rsplit_once("::").map(|v| v.1).unwrap_or(path).into()
194        } else {
195            let path = &self.attribute::<ComponentPath>().expect("No path for component").0;
196            path.rsplit_once("::").map(|v| v.1).unwrap_or(path).into()
197        }
198    }
199
200    /// A human-friendly name, if available. Corresponds to the [Name] attribute.
201    pub fn name(&self) -> Option<String> {
202        Some(self.attribute::<Name>()?.0.clone())
203    }
204
205    /// A human-friendly description, if available. Corresponds to the [Description] attribute.
206    pub fn description(&self) -> Option<String> {
207        Some(self.attribute::<Description>()?.0.clone())
208    }
209
210    pub fn type_name(&self) -> &'static str {
211        (self.vtable.get_type_name)()
212    }
213
214    pub fn type_id(&self) -> TypeId {
215        (self.vtable.get_type_id)()
216    }
217
218    #[inline]
219    /// Returns true if the entry is of type `T`
220    pub fn is<T: 'static>(&self) -> bool {
221        (self.vtable.get_type_id)() == TypeId::of::<T>()
222    }
223
224    pub(crate) fn new(index: u32, vtable: &'static ComponentVTable<()>) -> Self {
225        Self { index, vtable }
226    }
227
228    pub fn has_attribute<A: ComponentAttribute>(&self) -> bool {
229        (self.vtable.attributes)(*self).has::<A>()
230    }
231
232    pub fn attribute<A: ComponentAttribute>(&self) -> Option<AttributeGuard<A>> {
233        let guard = (self.vtable.attributes)(*self);
234        MappedRwLockReadGuard::try_map(guard, |store| store.get::<A>()).ok()
235    }
236
237    pub fn attributes(&self) -> AttributeStoreGuard {
238        (self.vtable.attributes)(*self)
239    }
240
241    pub fn attributes_mut(&self) -> AttributeStoreGuardMut {
242        (self.vtable.attributes_init)(*self)
243    }
244
245    pub fn as_debug<'a>(&self, value: &'a dyn Any) -> &'a dyn Debug {
246        struct NoDebug;
247        impl Debug for NoDebug {
248            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249                f.write_str("...")
250            }
251        }
252
253        if let Some(v) = self.attribute::<Debuggable>() {
254            v.as_debug(value)
255        } else {
256            &NoDebug
257        }
258    }
259
260    pub fn index(&self) -> u32 {
261        self.index
262    }
263
264    pub fn from_json(&self, value: &str) -> Result<ComponentEntry, serde_json::Error> {
265        self.attribute::<Serializable>()
266            .expect("Component is not serializable")
267            .deserializer(*self)
268            .deserialize(&mut serde_json::de::Deserializer::from_str(value))
269    }
270
271    /// Converts the **value** to json
272    pub fn to_json(&self, value: &ComponentEntry) -> Result<String, serde_json::Error> {
273        serde_json::to_string(self.attribute::<Serializable>().expect("Component is not serializable").serialize(value))
274    }
275
276    pub fn create_buffer(&self) -> Box<dyn IComponentBuffer> {
277        (self.vtable.impl_create_buffer)(*self)
278    }
279}
280
281impl Serialize for ComponentDesc {
282    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
283        serializer.serialize_str(&self.path())
284    }
285}
286
287impl<'de> Deserialize<'de> for ComponentDesc {
288    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289    where
290        D: serde::Deserializer<'de>,
291    {
292        struct BoxIComponentVisitor;
293
294        impl<'de> serde::de::Visitor<'de> for BoxIComponentVisitor {
295            type Value = ComponentDesc;
296
297            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
298                formatter.write_str("struct ComponentDesc")
299            }
300            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
301            where
302                E: de::Error,
303            {
304                let component = with_component_registry(|r| r.get_by_path(v));
305                match component {
306                    Some(comp) => Ok(comp),
307                    None => Err(de::Error::custom(format!("No such component: {v}"))),
308                }
309            }
310        }
311
312        deserializer.deserialize_str(BoxIComponentVisitor)
313    }
314}
315
316#[macro_export]
317/// Defines components to use within the ECS.
318///
319/// If the type is captured by [crate::PrimitiveComponent] and has a [crate::Name] and [crate::Description], these will be accessible by wasm.
320/// Please make sure to update the interface components if you update WASM-visible components.
321macro_rules! components {
322    ($ns: literal, { $($(#[$outer:meta])* $(@[$($attr: ty$([ $params: expr ])?),*])? $vis: vis $name:ident: $ty:ty,)*}) => {
323        $(
324            $crate::paste::paste! {
325                #[allow(non_upper_case_globals)]
326                #[doc(hidden)]
327                static [<comp_ $name>]: $crate::OnceCell<$crate::ComponentDesc> = $crate::OnceCell::new();
328
329                #[doc(hidden)]
330                fn [< __init_component_ $name>] (reg: &mut $crate::ComponentRegistry) -> $crate::ComponentDesc {
331                    fn init_attr(_component: $crate::Component<$ty>) -> $crate::parking_lot::RwLock<$crate::AttributeStore> {
332
333                        #[allow(unused_mut)]
334                        let mut store = $crate::AttributeStore::new();
335
336
337                        $( $(
338                            <$attr as $crate::AttributeConstructor::<$ty, _>>::construct(
339                                &mut store,
340                                ($($params),*)
341                            );
342                        )*)*
343
344                        $crate::parking_lot::RwLock::new(store)
345
346                    }
347
348                    static ATTRIBUTES: $crate::OnceCell<$crate::parking_lot::RwLock<$crate::AttributeStore>> = $crate::OnceCell::new();
349
350                    static PATH: &str = concat!("core::", $ns, "::", stringify!($name));
351
352                    static VTABLE: &$crate::ComponentVTable<$ty> = &$crate::ComponentVTable::construct(
353                        PATH,
354                        |desc| $crate::parking_lot::RwLockReadGuard::map(ATTRIBUTES.get_or_init(|| init_attr($crate::Component::new(desc))).read(), |v| v),
355                        |desc| $crate::parking_lot::RwLockWriteGuard::map(ATTRIBUTES.get_or_init(|| init_attr($crate::Component::new(desc))).write(), |v| v)
356                    );
357
358                    *[<comp_ $name>].get_or_init(|| {
359                        reg.register_static(PATH, unsafe { VTABLE.erase() } )
360                    })
361                }
362
363                $(#[$outer])*
364                pub fn $name() -> $crate::Component<$ty> {
365
366                    let desc = *[<comp_ $name>].get()
367                        .expect(concat!("Component: ", "core::", $ns, "::", stringify!($name), " is not initialized"));
368
369                    $crate::Component::new(desc)
370                }
371            }
372        )*
373
374
375        /// Initialize the components for the module
376        pub fn init_components() {
377                let mut reg = $crate::ComponentRegistry::get_mut();
378                $(
379                    $crate::paste::paste! {
380                        [< __init_component_ $name>](&mut reg);
381                    }
382                )*
383        }
384
385    }
386}
387
388#[cfg(test)]
389mod test {
390    use std::{ptr, sync::Arc};
391
392    use once_cell::sync::Lazy;
393    use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
394    use serde::de::DeserializeSeed;
395
396    use super::*;
397    use crate::{AttributeStore, ComponentVTable, MakeDefault, Networked, Store};
398
399    #[test]
400    fn manual_component() {
401        static ATTRIBUTES: Lazy<RwLock<AttributeStore>> = Lazy::new(Default::default);
402        static VTABLE: &ComponentVTable<String> = &ComponentVTable::construct(
403            "core::test::my_component",
404            |_| RwLockReadGuard::map(ATTRIBUTES.read(), |v| v),
405            |_| RwLockWriteGuard::map(ATTRIBUTES.write(), |v| v),
406        );
407
408        let component: Component<String> = Component::new(ComponentDesc::new(1, unsafe { VTABLE.erase() }));
409
410        let value = ComponentEntry::new(component, "Hello, World".into());
411
412        let value2 = value.clone();
413
414        let s = value.downcast_ref::<String>();
415        let s2 = value2.downcast_ref::<String>();
416
417        // Since they are cloned, they should not be reference equal
418        assert!(!ptr::eq(s as *const String, s2 as *const String));
419        // They are however value equal
420        assert_eq!(value.downcast_ref::<String>(), value2.downcast_ref::<String>());
421
422        assert_eq!(value.try_downcast_ref::<&str>(), None);
423    }
424
425    #[derive(PartialEq, Eq, Debug, Clone, serde::Serialize, serde::Deserialize)]
426    pub struct Person {
427        name: String,
428        age: i32,
429    }
430
431    #[test]
432    fn component_macro() {
433        components! ("component_macro",{
434            @[Serializable, Debuggable]
435            foo: String,
436            /// This is a person
437            @[Serializable, Debuggable]
438            person: Person,
439        });
440
441        init_components();
442
443        let component = foo();
444
445        assert_eq!(component.path_last(), "foo");
446
447        assert!(component.has_attribute::<Serializable>());
448
449        let p = Person { name: "Adam".into(), age: 28 };
450        let entry = ComponentEntry::new(person(), p);
451
452        let str = serde_json::to_string_pretty(entry.attribute::<Serializable>().unwrap().serialize(&entry)).unwrap();
453
454        eprintln!("Serialized: {str}");
455
456        let ser = person().attribute::<Serializable>().unwrap();
457
458        let value: ComponentEntry = ser.deserializer(person().desc()).deserialize(&mut serde_json::Deserializer::from_str(&str)).unwrap();
459
460        eprintln!("Value: {:?}", value.as_debug());
461
462        let p = entry.into_inner::<Person>();
463        assert_eq!(value.downcast_ref::<Person>(), &p);
464        assert_eq!(value.try_downcast_ref::<String>(), None);
465    }
466
467    #[test]
468    fn make_default() {
469        fn default_person() -> Person {
470            Person { age: 21, name: "unnamed".into() }
471        }
472
473        components! ("make_default", {
474            @[MakeDefault, Debuggable]
475            people: Vec<Person>,
476            @[MakeDefault[default_person], Debuggable, Store, Networked]
477            person: Person,
478        });
479        init_components();
480
481        let people_desc: ComponentDesc = people().desc();
482        let person_desc: ComponentDesc = person().desc();
483
484        let mut people = people_desc.attribute::<MakeDefault>().unwrap().make_default(people_desc);
485
486        let mut person = person_desc.attribute::<MakeDefault>().unwrap().make_default(person_desc);
487
488        assert_eq!(person.downcast_ref::<Person>(), &Person { age: 21, name: "unnamed".into() });
489
490        people.downcast_mut::<Vec<Person>>().push(person.downcast_cloned::<Person>());
491
492        assert_eq!(&people.downcast_mut::<Vec<Person>>()[0], person.downcast_ref::<Person>());
493        person.downcast_mut::<Person>().name = "Smith".to_string();
494        assert_ne!(&people.downcast_mut::<Vec<Person>>()[0], person.downcast_ref::<Person>());
495
496        eprintln!("people: {people:?}, person: {person:?}");
497    }
498
499    #[test]
500    fn test_take() {
501        components! ("test_take", {
502            @[Store]
503            my_component: Arc<String>,
504        });
505
506        init_components();
507        let shared = Arc::new("Foo".to_string());
508
509        {
510            let value = ComponentEntry::new(my_component(), shared.clone());
511            let value2 = ComponentEntry::new(my_component(), shared.clone());
512
513            assert_eq!(Arc::strong_count(&shared), 3);
514            drop(value);
515            assert_eq!(Arc::strong_count(&shared), 2);
516
517            let value = value2.into_inner::<Arc<String>>();
518            assert_eq!(Arc::strong_count(&shared), 2);
519            drop(value);
520            assert_eq!(Arc::strong_count(&shared), 1);
521        }
522
523        assert_eq!(Arc::strong_count(&shared), 1);
524    }
525
526    #[test]
527    fn leak_test() {
528        let shared = Arc::new("Foo".to_string());
529
530        components! ("leak_test", {
531            my_component: Arc<String>,
532        });
533
534        init_components();
535
536        {
537            let value = ComponentEntry::new(my_component(), shared.clone());
538            let value2 = ComponentEntry::new(my_component(), shared.clone());
539
540            assert_eq!(Arc::strong_count(&shared), 3);
541            drop(value);
542            assert_eq!(Arc::strong_count(&shared), 2);
543
544            let value3 = value2.clone();
545            let value4: Arc<String> = value2.downcast_cloned();
546            assert_eq!(Arc::strong_count(&shared), 4);
547            drop(value4);
548            assert_eq!(Arc::strong_count(&shared), 3);
549
550            assert_eq!(value3.downcast_ref::<Arc<String>>(), &shared);
551            assert_eq!(value3.downcast_ref::<Arc<String>>(), value2.downcast_ref());
552
553            assert!(!ptr::eq(value3.downcast_ref::<Arc<String>>() as *const Arc<String>, &shared as *const _));
554            assert!(!ptr::eq(value3.downcast_ref::<Arc<String>>() as *const Arc<String>, value2.downcast_ref::<Arc<String>>() as *const _));
555
556            assert!(ptr::eq(&**value3.downcast_ref::<Arc<String>>() as *const String, &*shared as *const _));
557        }
558
559        assert_eq!(Arc::strong_count(&shared), 1);
560    }
561}