ambient_ecs/
primitive_component.rs

1use std::{any::TypeId, collections::HashMap};
2
3use glam::{Mat4, Quat, UVec2, UVec3, UVec4, Vec2, Vec3, Vec4};
4use once_cell::sync::Lazy;
5use paste::paste;
6
7use crate::{
8    AttributeConstructor, AttributeStore, ComponentDesc, ComponentRegistry, ComponentVTable, Description, EntityId,
9    ExternalComponentAttributes, Name,
10};
11
12use ambient_shared_types::primitive_component_definitions;
13
14// implementation
15macro_rules! build_attribute_registration {
16    ($type:ty, $store:ident, $attributes:ident) => {{
17        if let Some(name) = $attributes.name {
18            <Name as AttributeConstructor<$type, _>>::construct(&mut $store, &name);
19        }
20        if let Some(description) = $attributes.description {
21            <Description as AttributeConstructor<$type, _>>::construct(&mut $store, &description);
22        }
23        $attributes.flags.construct_for_store::<$type>(&mut $store);
24
25        static VTABLE: &ComponentVTable<$type> = &ComponentVTable::construct_external();
26        unsafe { VTABLE.erase() }
27    }};
28}
29
30macro_rules! make_primitive_component {
31    ($(($value:ident, $type:ty)),*) => {
32        paste! {
33            #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34            pub struct PrimitiveComponent {
35                pub ty: PrimitiveComponentType,
36                pub desc: ComponentDesc,
37            }
38
39            #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
40            #[derive(serde::Serialize, serde::Deserialize)]
41            pub enum PrimitiveComponentContainerType {
42                Vec,
43                Option
44            }
45            impl PrimitiveComponentContainerType {
46                pub fn as_str(&self) -> &'static str {
47                    match self {
48                        Self::Vec => "Vec",
49                        Self::Option => "Option",
50                    }
51                }
52            }
53
54            #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
55            #[derive(serde::Serialize, serde::Deserialize)]
56            pub enum PrimitiveComponentType {
57                $($value), *,
58                $([< Vec $value >]), *,
59                $([< Option$value >]), *,
60            }
61
62            impl TryFrom<&str> for PrimitiveComponentType {
63                type Error = &'static str;
64
65                fn try_from(value: &str) -> Result<Self, Self::Error> {
66                    match value {
67                        $(stringify!($value) => Ok(Self::$value),)*
68                        "Vec" | "Option" => Err("The specified type is a container type, not primitive"),
69                        _ => Err("Unsupported type")
70                    }
71                }
72            }
73
74            impl PrimitiveComponent {
75                pub fn as_component(&self) -> ComponentDesc {
76                    self.desc
77                }
78            }
79
80            impl PrimitiveComponentType {
81                /// Not defined for the container types; use [Self::decompose_container_type].
82                pub fn as_str(&self) -> Option<&'static str> {
83                    match self {
84                        $(Self::$value => Some(stringify!($value)),)*
85                        _ => None,
86                    }
87                }
88
89                pub fn to_vec_type(&self) -> Option<Self> {
90                    match self {
91                        $(Self::$value => Some(Self::[<Vec $value>]),)*
92                        _ => None
93                    }
94                }
95
96                pub fn to_option_type(&self) -> Option<Self> {
97                    match self {
98                        $(Self::$value => Some(Self::[<Option $value>]),)*
99                        _ => None
100                    }
101                }
102
103                pub fn decompose_container_type(&self) -> Option<(PrimitiveComponentContainerType, Self)> {
104                    match self {
105                        $(Self::[<Vec $value>] => Some((PrimitiveComponentContainerType::Vec, Self::$value)),)*
106                        $(Self::[<Option $value>] => Some((PrimitiveComponentContainerType::Option, Self::$value)),)*
107                        _ => None
108                    }
109                }
110
111                pub(crate) fn register(&self, reg: &mut ComponentRegistry, path: &str, attributes: ExternalComponentAttributes) {
112                    let mut store = AttributeStore::new();
113                    let vtable = match self {
114                        $(
115                            PrimitiveComponentType::$value => {
116                                build_attribute_registration!($type, store, attributes)
117                            },
118                            PrimitiveComponentType::[< Vec $value >] => {
119                                build_attribute_registration!(Vec<$type>, store, attributes)
120                            },
121                            PrimitiveComponentType::[< Option $value >] => {
122                                build_attribute_registration!(Option<$type>, store, attributes)
123                            },
124                        )*
125                    };
126
127                    reg.register_external(path.into(), vtable, store);
128                }
129            }
130            impl PartialEq<PrimitiveComponentType> for PrimitiveComponent {
131                fn eq(&self, other: &PrimitiveComponentType) -> bool {
132                    &self.ty == other
133                }
134            }
135
136            pub static TYPE_ID_TO_PRIMITIVE_TYPE: Lazy<HashMap<TypeId, PrimitiveComponentType>> = Lazy::new(|| {
137                HashMap::from_iter([
138                    $((TypeId::of::<$type>(), PrimitiveComponentType::$value),)*
139                    $((TypeId::of::<Vec<$type>>(), PrimitiveComponentType::[<Vec $value>]),)*
140                    $((TypeId::of::<Option<$type>>(), PrimitiveComponentType::[<Option $value>]),)*
141                ])
142            });
143        }
144    }
145}
146
147primitive_component_definitions!(make_primitive_component);